//============================================================================================
/**
 * @file	pkthln_jump.c
 * @brief	ジャンプ
 * @author	Nozomu Saito
 */
//============================================================================================

#include "pkthln_jump.h"
#include "../../pkthln_obj_common.h"
#include "../../poke_clact.h"
#include "../pkthln_clact.h"
#include "../pkthln_act_def.h"

#include "system/arc_tool.h"
#include "system/snd_tool.h"
#include "system/wipe.h"
#include "system/render_oam.h"
#include "system/fontproc.h"
#include "touchpanel.h"

#include "../../pkthln_comm_pack.h"
#include "../../poke_clact_move.h"

#include "../event_se_def.h"

#include "system/arc_util.h"

#include "jump_comm.h"
#include "jump_obj_pri.h"

#include "../../cmn_res.h"
#include "../../pkthln_poke_act.h"

#include "jump_lamp.h"
#include "jump_ai.h"

//成績作成用
#include "system/msgdata_util.h"
#include "msgdata/msg.naix"
#include "msgdata/msg_pokethlon.h"

#include "../pkthln_evt_info.naix"
#include "pkthev_jump.naix"

//同期待ち
#include "../../pkthln_frame_seq_def.h"	//for	FRAME_SEQ_CALLBACK_WAIT


// 構造体が想定のサイズとなっているかチェック
#ifdef PM_DEBUG
#ifdef _NITRO
SDK_COMPILER_ASSERT(sizeof(JUMP_PARENT_DATA) == 36);
#endif
extern DEBUG_PKTHLN_WORK DebugPkthlnWk;
#endif		//PM_DEBUG

#define JUMP_HEAP_SIZE	(0x50000)

#define JUMP_EVENT_POKE_NUM	(ENTRY_MAX)
#define PCLACT_TCB_PRIORITY	(0)

#define START_POKE_MARGINE	( 64 )
#define START_POKE_POS_X	(64)
#define START_POKE_POS_Y	(96)

#define BG_PRI	(1)

#define JUMP_OBJ_PALETTE_NUM	(4)
#define TIMER_ACT_NUM	(2)

#define ACT_MAX	(1+1+TIMER_ACT_NUM+((JUMP_EVENT_POKE_NUM*3)+LAMP_NUM+LAMP_NUM+LAMP_NUM+4+1)*2+ENTRY_MAX)
//カウントダウン+ラストカウント+タイム数字(カンマ含む)4+(ポケ3+気絶3+ヒット3+ランプ29+ポイント29+取得エフェクト29+旗4+時計1)*2+ペン3
#define JUMP_EVENT_OBJ_NUM	(JUMP_EVENT_POKE_NUM + ACT_MAX + 1)
#define JUMP_EVENT_PAL_NUM	(JUMP_EVENT_POKE_NUM*2+ 4*2 + 1)	//上下ポケ3*2　上下パレット4*2　共通リソース



#define MAIN_SUB_DIST	(192*FX32_ONE)	//上下続いてる
#define GROUND_BASE_OFS	(96 * FX32_ONE)


#define WATCH_POS_X	(21*8*FX32_ONE)
#define WATCH_POS_Y	(8*FX32_ONE)
#define MY_FLAG_POS_X	((3*8-2)*FX32_ONE)
#define MY_FLAG_POS_Y	(9*8*FX32_ONE)
#define OTHER_FLAG_POS_X	((21*8-2)*FX32_ONE)
#define OTHER_FLAG_POS_Y_BASE	(5*8*FX32_ONE)
#define OTHER_FLAG_POS_Y_MARGINE	(2*8*FX32_ONE)

#define TIMER_ACT_POS_X	(24*8)
#define TIMER_ACT_POS_Y	(8)

#define COMBO_MAX		(5)
#define GAME_SCORE_MAX	(999)

#define SCORE_NUMBER_W	(4)		//得点用数字横キャラ幅
#define SCORE_NUMBER_H	(8)		//得点用数字縦キャラ幅
#define SCORE_DIGI_MAX	(3)		//得点は最大3桁
#define SCORE_DISP_START_X	(1)	//得点描画開始X位置（キャラ）
#define SCORE_DISP_START_Y	(0)		//得点描画開始Y位置（キャラ）
#define NUMBER_SCR_NUM_W	(5)	//数字スクリーンデータの横の数字の数0〜4	スクリーンデータに依存
#define NUMBER_SCR_NUM_H	(2)	//数字スクリーンデータの縦の数字の数5〜9	スクリーンデータに依存

#define MSG_BG	(GF_BGL_FRAME2_S)
#define REC_BG	(GF_BGL_FRAME3_M)

#define WIN_NAME1_PX	(4)
#define WIN_NAME1_PY	(8)
#define WIN_NAME2_PX	(22)
#define WIN_NAME2_PY	(4)
#define WIN_NAME3_PX	(22)
#define WIN_NAME3_PY	(6)
#define WIN_NAME4_PX	(22)
#define WIN_NAME4_PY	(8)
#define WIN_NAME_SX		(10)
#define WIN_NAME_SY		(2)
#define WIN_NAME_SIZE	( WIN_NAME_SX * WIN_NAME_SY )
#define	BAGCOL_N_WHITE	( GF_PRINTCOLOR_MAKE( 15, 14, 0 ) )		// フォントカラー：白
#define	COL_N_WHITE	( GF_PRINTCOLOR_MAKE( 15, 14, 0 ) )		// フォントカラー：白
#define WIN_MAX			(ENTRY_MEMBER_NUM_MAX+1)		//プレーヤー名4+ニューレコード表示1
#define	JUMP_SYS_FONT_PAL	(15)
#define	REC_FONT_PAL	(15)

#define WIN_CGX_BASE	(1)
#define WIN_NAME1_CGX	(WIN_CGX_BASE)
#define WIN_NAME2_CGX	(WIN_NAME1_CGX + WIN_NAME_SIZE )
#define WIN_NAME3_CGX	(WIN_NAME2_CGX + WIN_NAME_SIZE )
#define WIN_NAME4_CGX	(WIN_NAME3_CGX + WIN_NAME_SIZE )
#define WIN_REC_CGX	(WIN_NAME4_CGX + WIN_NAME_SIZE )

////////////////////////////////////////////////////////////////////////////
#define JUMP_POINT_NUM	(128)
#define CONT_TOUCH_MAX	(7)		//ストローク最大時間
#define CONF_3D_TO_2D	(64)		//3D＞2Dへの変換係数

#define CAMERA_PERS	( 0xa4 )
#define CAMERA_DISTANCE	( 0x64000 )
#define CAMERA_SHIFT_Y	( 0x0 )
#define CAMERA_SHIFT_Z	( 0x1000 )		//正射影なので適当

#define EXPAND_VAL	(1)

#define ADD_SPEED	(FX32_ONE/12.0)	//反発値
#define GRAVITY		(FX32_ONE / 32.0)

#define DEC_SPEED	(FX32_ONE/5.0)//減速値　反発値より大きい値にする

#define JUMP_SPEED_MAX	(2200)

#define SIDE_SPEED_MAX	(10)
#define DEC_SIDE_SPEED	(2)

#define SIDE_SP_CONF		(4)	//横ストローク係数

#define JUMP_DIV_CONF		(12)	//ポケモンジャンプパラメータ係数
#define STEP_DIV_CONF		(12)	//ポケモン横とびパラメータ係数
#define PANIC_DIV_CONF		(30)	//ポケモン気絶時間パラメータ係数


#define STROKE_MAX	(0x70000)		//ストローク距離最大値
#define X_MIN	(32)
#define X_MAX	(255-32)

#define MARGE_1	(1)
#define MARGE_2	(2)
#define MARGE_3	(4)

#define MARGE_ALL	(MARGE_1|MARGE_2|MARGE_3)

#define BALL_Y_MIN_LIMIT	(-FX32_ONE*1.5)

#define NPC_SCORE_BASE	(80)

#define HIT_SE_IDX	(3)

//デバッグ機能
#ifdef PM_DEBUG
//#define DEBUG_3D		//3Dデバッグ バネシミュレーター上にデバッグ用ポリゴンを表示
#define D_Print(exp, ...) (exp)? OS_Printf(__VA_ARGS__) : ((void)0) 	//条件を満たしたらプリント

///#define DEBUG_MIN_TIME			//デバッグ短縮時間
#endif

#ifdef DEBUG_MIN_TIME
#define GAME_TIME		(30)		//デバッグ短縮ゲーム時間
#else
#define GAME_TIME		(60*30)		//ゲーム時間60秒
#endif

typedef struct SEET_DAT_tag
{
	fx32 Point[JUMP_POINT_NUM];
	fx32 TempPoint[ENTRY_MAX][JUMP_POINT_NUM];
	fx32 JPMargine[ENTRY_MAX][JUMP_POINT_NUM];
	int JumpPoint[ENTRY_MAX];
}SEET_DAT;

typedef struct JUMP_POKE_tag
{
	//アクターポインタ
	POKE_ACT_PTR PokeActPtr;		//ポケモンアクター
	//気絶アクター
	PKTHLN_ACT_PTR	PanicActPtr;
	//座標
	VecFx32 DispPos;
	//有効射程
	fx32 Range;
	fx32 DispXSpd;
	fx32 DispXTmp;
	u16 Score;
	u16 Dir;
	u16 Combo;
	u8 PanicState;
	u8 PanicCount;
	u8 FirstShot;
	u8 Hit[ENTRY_MAX];

	int Jump;
	int PanicTime;
	int Step;
}JUMP_POKE;

typedef struct J_BALL_tag
{
	fx32 Speed;
	VecFx32 Pos;
	int Fly;
	int Move;
	fx32 UpdnSpeed;	//打ち出したとき・シート設置したときのスピード
}BALL;

typedef struct PKTHLN_JUMP_tag
{
	GF_BGL_INI *bgl;
	GF_BGL_BMPWIN	Win[WIN_MAX];			// BMPウィンドウデータ
	int HeapID;
	void *ScoreBgArc;
	NNSG2dScreenData *ScoreScrnData;
	//アクター
	PKTHLN_CLACT_CNT_PTR ActCntPtr;
	//時計
	PKTHLN_ACT_PTR WatchActPtr;
	//旗
	PKTHLN_ACT_PTR FlagActPtr[ENTRY_MEMBER_NUM_MAX];
	//ヒットエフェクト
	PKTHLN_ACT_PTR HitActPtr[JUMP_EVENT_POKE_NUM];
	//タイマー数字
	CLACT_WORK_PTR	TimeNumActPtr[TIMER_ACT_NUM];	//秒2桁
	//ランプ制御
	LAMP_CNT_PTR LampCntPtr;

	JUMP_POKE	Poke[ENTRY_MAX];

	JUMP_AI_CNT_PTR AICntPtr;

	int Time;

	u8 HoldPoke;
	u8 CountTouchFrame;
	u8 PointGet;
	u8 HitIdx;

	VecFx32 HitVec[JUMP_EVENT_POKE_NUM];
	u8 HitFlg[JUMP_EVENT_POKE_NUM];
	u8 dummy;

	VecFx32 NowPoint;
	VecFx32 Stroke;

	NNSG2dScreenData *CounterScrnData;

	CMN_RES_CNT_PTR	CmnResCntPtr;
	POKE_ACT_CNT_PTR PokeActCntPtr;

	GF_CAMERA_PTR CameraPtr;
	VecFx32 CameraTarget;

	SEET_DAT SeetDat;

	BALL	Ball[ENTRY_MAX];
	NNSG2dCellTransferState* 	TransferSt;
}PKTHLN_JUMP;

typedef struct JUMP_PARAM_tag
{
	int Jump[5];
	int PanicTime[5];
	int Step[5];
}JUMP_PARAM;

static void SetVramBank(void);

static BOOL JUMP_Func_Phase1(PKTHLN_PTR work, u8 *seq);
static BOOL JUMP_Func_Phase2(PKTHLN_PTR work, u8 *seq);


static void BgInit(GF_BGL_INI * ini);
static void SetGraphic(PKTHLN_JUMP_PTR ptr);
static void SetObj(PKTHLN_CLACT_CNT_PTR pActCntPtr);
static void SetAct( PKTHLN_JUMP_PTR ptr, PKTHLN_CLACT_CNT_PTR pActCntPtr);
static void SetActPos( PKTHLN_JUMP_PTR ptr, const u8 inMyNetID);
static void DispTotalScore(PKTHLN_JUMP_PTR ptr);
static void DispScore(PKTHLN_JUMP_PTR ptr, const u16 inScore);
static void DispTime(PKTHLN_JUMP_PTR ptr, const u16 inTime);
static void WriteName( PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr );
static void CreateBmpWin( PKTHLN_JUMP_PTR ptr );
static void SetRecordStr(PKTHLN_JUMP_PTR ptr, const u16 inScore);
static void DecSideSpeed(JUMP_POKE *poke);
static void SetPokeParam(	PKTHLN_PTR work, const JUMP_PARAM *inData,
							const u8 inIdx, JUMP_POKE *outPoke);
static BOOL HitCheck(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr);
static BOOL ControlMain(PKTHLN_PTR work);
static void SetDraw(PKTHLN_PTR work);
static void CommMain(PKTHLN_PTR work);
static void SetPokemonDrawPos(PKTHLN_PTR work);
static void FlagAnm(PKTHLN_PTR work);
static void GetStrokeVec(const u8 inTpX, const u8 inTpY, const VecFx32 *inNowPoint, VecFx32 *outPoint);

static u8 CheckPokeTouch(PKTHLN_JUMP_PTR ptr, const u16 inX, const u16 inY);
static BOOL CheckCircle(const VecFx32 *inVec1, const fx32 inRange1,
		const VecFx32 *inVec2, const fx32 inRange2);
static void ShotPoke(PKTHLN_JUMP_PTR ptr, const u8 inIdx, const VecFx32 *inStroke);
static void MakeConectData(PKTHLN_JUMP_PTR ptr);


static void Setup3D(PKTHLN_JUMP_PTR ptr);
static void Draw3D(PKTHLN_JUMP_PTR ptr);
static void InitCamera( PKTHLN_JUMP_PTR ptr );

static void MargeSeet(SEET_DAT *seet);
static void MargeSeetEx(SEET_DAT *seet, const u8 inMargeFlg, fx32 *outPoint);
static void Fix(SEET_DAT *seet, const u8 inIdx, const u8 inTmp1, const u8 inTmp2);
static u8 CalcPoint(JUMP_POKE *poke);
static void MoveBallAll(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr);
static void MoveBall(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr, const u8 inIdx);
static void MoveSide(JUMP_POKE *poke, const BALL *ball);

#ifdef PM_DEBUG
static void DebugCameraInput(GF_CAMERA_PTR camera_ptr);
static void DebugPritnfCameraInfo(GF_CAMERA_PTR camera_ptr);
static int debug_side;
static int debug_pin_no;
static u8 debug_stop;

static int debug_count1 = 0;
static int debug_count2 = 0;

#endif //PM_DEBUG
static void SetSeetPoint( const u32 inX, const fx32 inY, fx32 *outSeet);
static void AdsorbBall(PKTHLN_JUMP_PTR ptr);
static void SetTmpPoint(PKTHLN_JUMP_PTR ptr, const u8 inIdx, const u8 inPos, const fx32 inVal);

PKTHLN_FUNC JumpFuncTbl[] = {
	JUMP_Func_Phase1,
	JUMP_Func_Phase2,
};

enum {
	JUMP_SEQ_PHASE1,
	JUMP_SEQ_PHASE2,
};

//タイマーアクターX座標
static const u8 TimerActPosX[TIMER_ACT_NUM] = {
	TIMER_ACT_POS_X, TIMER_ACT_POS_X+16,
};
//タイマーアクターアニメ番号（セルアニメデータ依存）
static const u8 DefaultTimerActAnm[TIMER_ACT_NUM] = {
	1,1,
};

static const BMPWIN_DAT JumpEvtBmpData[] =
{

	{	// 0:トレーナー名
		MSG_BG, WIN_NAME1_PX, WIN_NAME1_PY,
		WIN_NAME_SX, WIN_NAME_SY, JUMP_SYS_FONT_PAL, WIN_NAME1_CGX
	},
	{	// 1:トレーナー名
		MSG_BG, WIN_NAME2_PX, WIN_NAME2_PY,
		WIN_NAME_SX, WIN_NAME_SY, JUMP_SYS_FONT_PAL, WIN_NAME2_CGX
	},
	{	// 2:トレーナー名
		MSG_BG, WIN_NAME3_PX, WIN_NAME3_PY,
		WIN_NAME_SX, WIN_NAME_SY, JUMP_SYS_FONT_PAL, WIN_NAME3_CGX
	},
	{	// 3:トレーナー名
		MSG_BG, WIN_NAME4_PX, WIN_NAME4_PY,
		WIN_NAME_SX, WIN_NAME_SY, JUMP_SYS_FONT_PAL, WIN_NAME4_CGX
	},
	{	//ニューレコード
		REC_BG, WIN_REC_PX, WIN_REC_PY,
		WIN_REC_SX, WIN_REC_SY, REC_FONT_PAL, WIN_REC_CGX
	}
};

static u8 SndPlayer[JUMP_EVENT_POKE_NUM+1] = {
	PLAYER_SE_1,
	PLAYER_SE_2,
	PLAYER_SE_3,
	PLAYER_SE_4,		//ぶつかり音で共通使用
};

const int SndPitch[COMBO_MAX] = {
	THLON_JUMP_PITCH_LV1,
	THLON_JUMP_PITCH_LV2,
	THLON_JUMP_PITCH_LV3,
	THLON_JUMP_PITCH_LV4,
	THLON_JUMP_PITCH_LV5,
};


//--------------------------------------------------------------------------------------------
/**
 * 初期化関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
PTH_RC PE_JUMP_InitFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);
	u8 seq = PTFrame_GetSubSeq(work);
	switch(seq){
	case 0:
		{
			int heap_id;
			sys_CreateHeap( HEAPID_POKETHLON, HEAPID_PT_JUMP, JUMP_HEAP_SIZE );
			heap_id = HEAPID_PT_JUMP;
			sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
			sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

			GF_Disp_GX_VisibleControlInit();
			GF_Disp_GXS_VisibleControlInit();
			GX_SetVisiblePlane( 0 );
			GXS_SetVisiblePlane( 0 );

			//VRAMバンク割り当て
			SetVramBank();
			//アプリケーションメモリー
			ptr = PTFrame_AllocEventWork(work, sizeof(PKTHLN_JUMP));
			MI_CpuClear8( ptr, sizeof(PKTHLN_JUMP));

			//BGLアロケーション
			ptr->bgl = GF_BGL_BglIniAlloc(heap_id);

			//レコード表示ＢＧのセット
			PTFrame_SetRecBGMask(work, GX_PLANEMASK_BG3);

			{
				CHAR_MANAGER_MAKE cm;
				cm.CharDataNum = JUMP_EVENT_OBJ_NUM;
				cm.VramTransAreaMain = 256*1024;
				cm.VramTransAreaSub = 16*1024;
				cm.heap = PTFrame_GetHeapID(work);

				//キャラ・パレットマネージャ初期化
				PKTHLN_OBJ_COMMON_InitCharPlttManager(	&cm,
														JUMP_EVENT_PAL_NUM,
														heap_id,
														GX_OBJVRAMMODE_CHAR_1D_256K,
														GX_OBJVRAMMODE_CHAR_1D_256K);
			}

			// OAMマネージャーの初期化
			NNS_G2dInitOamManagerModule();

			// 共有OAMマネージャ作成
			// レンダラ用OAMマネージャ作成
			// ここで作成したOAMマネージャをみんなで共有する
			REND_OAMInit(
					0, 126,		// メイン画面OAM管理領域
					0, 32,		// メイン画面アフィン管理領域
					0, 126,		// サブ画面OAM管理領域
					0, 32,		// サブ画面アフィン管理領域
					heap_id);
			ptr->HeapID = heap_id;
		}

		//タッチフォントロード
		FontProc_LoadFont(FONT_TOUCH, ptr->HeapID);

		BgInit(ptr->bgl);

		Setup3D(ptr);
		//下画面をメインにする
		sys.disp3DSW = DISP_3D_TO_SUB;
		GF_Disp_DispSelect();

		initVramTransferManagerHeap( ENTRY_MAX*4, ptr->HeapID );
		ptr->TransferSt = InitCellTransfer(ENTRY_MAX*4, ptr->HeapID);

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 1:

		//ランプコントローラ初期化
		ptr->LampCntPtr = Lmp_Init(ptr->HeapID);
		//AIコントローラ初期化
		ptr->AICntPtr = JumpAI_Init( ptr->HeapID,
									 ENTRY_MEMBER_NUM_MAX-PTFrame_GetPlayerNum(work),
									 PTFrame_GetGameType(work),
									 PTFrame_GetEvtComCmnData(work),
									 work );

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 2:
		{
			int i;
			CLACT_WORK_PTR act_ptr;
			PKTHLN_ACT_SETUP_PRM param = {
				ACT_MAX,1,{1,1,1,1}
			};
			ptr->ActCntPtr = PkthlnClAct_Init(ptr->HeapID, &param);

			//上下画面幅設定
			PkthlnClAct_SetDispDistance(ptr->ActCntPtr,
										0, MAIN_SUB_DIST,
										0, 0 );
			//ポケモンアクター
			ptr->PokeActCntPtr = PokeAct_Init( ptr->HeapID, JUMP_EVENT_POKE_NUM, PRI_POKE,
									  NULL, PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr) );	//共通リソース使用しない

			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 0, RES_CODE_JUMP);

			SetObj(ptr->ActCntPtr);
			//トランス
			PkthlnClAct_Trans(ptr->ActCntPtr);
		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 3:
		{
			int i;
			MONS_INFO info[JUMP_EVENT_POKE_NUM];
			PCLACT_SET_PARAM param;
			u8 net_id;

			net_id = PTFrameGetCurrentID(work);
			for(i=0;i<JUMP_EVENT_POKE_NUM;i++){
				PTFrame_SetMonsInfo(work, net_id, i, &info[i]);
				param.ShadowPos[i] =
					PTFrame_GetPokeShdwPosType(PTFrame_GetPkthlnParam(work, net_id, i));
			}
			param.Quick = 0;
			param.BGPriority = 1;
			param.Trans = 1;
			param.ResVramType = NNS_G2D_VRAM_TYPE_MAX;
			param.DrawArea = NNS_G2D_VRAM_TYPE_MAX;

			PokeAct_SetPokeActor(	ptr->PokeActCntPtr, JUMP_EVENT_POKE_NUM,
									info, &param,
									PCLACT_TCB_PRIORITY,
									0 );
		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 4:
		if ( PokeAct_CheckActSetTask(ptr->PokeActCntPtr) ){
			int i;
			EVT_HIT_DATA hit_data;
			PEN_POS	pen_pos[JUMP_EVENT_POKE_NUM];
			//共通リソース
			//※ポケモンを上下ぶち抜きで使用するため、ポケモンのパレット位置を上下合わせる必要があるので、リソース登録をポケモンの後にする
			ptr->CmnResCntPtr = CmnRes_Init( ptr->HeapID,
											 CMN_RES_COUNTER_BIT|CMN_RES_F2X4_BIT|CMN_RES_NEW_REC_BIT|CMN_RES_F2X2S256_BIT|CMN_RES_PEN_M_BIT,
											 NNS_G2D_VRAM_TYPE_2DMAIN );
			//カウントダウンアクター
			{
				CLACT_WORK_PTR	*act_adr;
				act_adr = PTFrame_SetCountDown( work, MAIN_SUB_DIST/FX32_ONE, ptr->CmnResCntPtr, ptr->ActCntPtr );
				//プライオリティセット
				CLACT_DrawPriorityChg( *act_adr, PRI_COUNT );
			}

			PTFrame_SetDefaultVBlankFunc(ptr->bgl);	// VBlankセット
			//描画を許可
			PTFrame_SetDraw(work, TRUE);

			ArchiveDataLoad(hit_data.Data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_jump_hit_bin);
			//ポケセルアクター可視化
			for (i=0;i<JUMP_EVENT_POKE_NUM;i++){
				POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
				PokeAct_DispCnt(poke_ptr, 1);	//表示
				//ポケモン初期位置
				{
					JUMP_POKE *jump_poke;
					jump_poke = &ptr->Poke[i];
					jump_poke->PokeActPtr = poke_ptr;
					//あたり判定データセット
					{
						HIT_TYPE hit_type;
						hit_type = PTFrame_GetPokeHitType(PTFrame_GetPkthlnParam(work, 0, i));
						PokeAct_SetHitData(poke_ptr, hit_data.Data[hit_type-1].Ofs, hit_data.Data[hit_type-1].Range);
					}

					//位置決定
					{
						int sx,sy,tx,ty;
						int range;
						//影の位置
						sx = START_POKE_POS_X + (START_POKE_MARGINE * i);
						sy = START_POKE_POS_Y + (MAIN_SUB_DIST/FX32_ONE);

						//向きセット
						PokeAct_SetDir(poke_ptr, POKE_DIR_DOWN);
						//アクター位置セット
						PokeAct_SetPosShadow(poke_ptr, sx, sy);

						//タッチ半径セット
						range = PTFrame_GetPokeTouchRange();
						PokeAct_SetTouchRange(poke_ptr, range);

						jump_poke->DispPos.x = sx*FX32_ONE;
						jump_poke->DispPos.y = sy*FX32_ONE;
						jump_poke->DispXTmp = sx*FX32_ONE;

						//タッチ中心座標取得
						PokeAct_GetTouchPosByShadowPos(poke_ptr, sx, sy, &tx, &ty);

						pen_pos[i].X = tx;
						pen_pos[i].Y = ty;

					}//位置決定
				} //ポケモン初期位置
			}	//end for

			//ペンアクター表示
			PTFrame_SetPen( work, 0, ptr->CmnResCntPtr, ptr->ActCntPtr,
						    NNS_G2D_VRAM_TYPE_2DMAIN, JUMP_EVENT_POKE_NUM,  pen_pos);


			{
				ptr->HoldPoke = JUMP_EVENT_POKE_NUM;
			}

			SetGraphic(ptr);
			SetAct(ptr, ptr->ActCntPtr);

			CreateBmpWin( ptr );

			//OBJの初期位置をセット
			SetActPos( ptr, PTFrameGetCurrentID(work));

			//次のシーケンスへ
			PTFrame_IncSubSeq(work);

		}
		break;
	case 5:
		{
			int i;
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_BG0, VISIBLE_ON );
			//ＯＢＪの表示
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// MAIN DISP OBJ ON
			GF_Disp_GXS_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// SUB DISP OBJ ON

			{
				JUMP_PARAM data;
				int i;
				JUMP_POKE *jump_poke;
				ArchiveDataLoad(&data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_jump_bin);

				//パラメータ格納
				for(i=0;i<ENTRY_MAX;i++){
					jump_poke = &ptr->Poke[i];
					SetPokeParam(work, &data, i, jump_poke);
				}

				if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){
					//AI用にポケモンデータをセットアップ
///					JumpAI_SetupPokeInfo( ptr->AICntPtr, i, stl_poke );
				}
			}

			//ゲーム時間セット
			ptr->Time = GAME_TIME;

			//開始時間表示
			DispTime(ptr, ptr->Time);
			//名前表示
			WriteName( work, ptr );

			//シートデータ初期化
			for(i=0;i<JUMP_POINT_NUM;i++){
				ptr->SeetDat.Point[i] = 0;
				ptr->SeetDat.TempPoint[0][i] = 0;
				ptr->SeetDat.TempPoint[1][i] = 0;
				ptr->SeetDat.TempPoint[2][i] = 0;
				ptr->SeetDat.JPMargine[0][i] = 0;
				ptr->SeetDat.JPMargine[1][i] = 0;
				ptr->SeetDat.JPMargine[2][i] = 0;
#if 0
#ifdef PM_DEBUG
				debug_side = 64;
				debug_pin_no = 0;
				debug_stop = 0;
#endif
#endif
			}
			//ボール関連
			for(i=0;i<ENTRY_MAX;i++){
				int x;
				ptr->Ball[i].Pos.y = 0;
				x = START_POKE_POS_X + (START_POKE_MARGINE * i);
				ptr->SeetDat.JumpPoint[i] = x/2;
				ptr->Ball[i].Pos.x = ((float)x/64.0 - 2.0 )*FX32_ONE;

				ptr->Poke[i].FirstShot = 1;
			}

			//通信アイコン
			WirelessIconEasyPokethlon( NNS_G2D_VRAM_TYPE_2DMAIN );

		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 6:
		//初回得点表示
		DispTotalScore(ptr);
		//初期化終了
		sys_PrintHeapFreeSize( ptr->HeapID );
		return PTH_RC_END;
	}
	return PTH_RC_LOOP;
}

//--------------------------------------------------------------------------------------------
/**
 * 描画関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_JUMP_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	PkthlnClAct_Draw(ptr->ActCntPtr);

	UpdateCellTransfer();
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * 競技結果計算関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_JUMP_ResultFunc(PKTHLN_PTR work, void *pParam)
{
	int i,j;
	RSLT_PTR result_ptr;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	OS_Printf("競技結果データ作成\n");

	result_ptr = PTFrame_GetResultPtr(work);
	RSLT_Setup( result_ptr  );

	for( i=0;i<ENTRY_MEMBER_NUM_MAX;i++ ){
		int rec;
		rec = PTFrame_GetEvtResult(work, i);

		RSLT_SetResult( work, result_ptr, i, rec,
							0, 3, msg_pkthln_rs_K6 );
	}

	//ソート
	RSLT_Sort(result_ptr, SORT_REC_LARGE);
	//得点セット
	PTC_CalcPoint(result_ptr, PKTHLN_EVT_JUMP);

	//総得点に加算
	RSLT_AddTotalScore(result_ptr);

	//競技得点セット
	RSLT_SetEvtScore(result_ptr, PKTHLN_EVT_JUMP);
	return TRUE;
}


//--------------------------------------------------------------------------------------------
/**
 * 終了関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_JUMP_EndFunc(PKTHLN_PTR work, void *pParam)
{
	int i;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	// 通信アイコン撤去
	WirelessIconEasyEnd();

	//カメラ解放
	GFC_FreeCamera(ptr->CameraPtr);

	//ランプコントローラ解放
	Lmp_End(ptr->LampCntPtr);

	//スクリーンアーカイブ解放
	sys_FreeMemoryEz(ptr->ScoreBgArc);

	//BG削除
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME3_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_S );

	for(i=0;i<WIN_MAX;i++){
		//BMP
		GF_BGL_BmpWinDel( &ptr->Win[i] );
	}

	//BGL解放
	sys_FreeMemoryEz(ptr->bgl);

	//共有データクリア
	PTFrame_ClearEvtShareDataPtr(work);


	//アクター解放
	PkthlnClAct_Free(ptr->ActCntPtr);

	//ポケアクターコントローラ解放
	PokeAct_Free(ptr->PokeActCntPtr);
	//共通リソースコントローラ解放
	CmnRes_Free(ptr->CmnResCntPtr);
	//AIコントローラー解放
	JumpAI_End(ptr->AICntPtr);

	//タッチフォントアンロード
	FontProc_UnloadFont(FONT_TOUCH);

	//OAMレンダラー破棄
	REND_OAM_Delete();

	DeleteCharManager();
	DeletePlttManager();

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	// 上下画面を元に戻しておく
	sys.disp3DSW = DISP_3D_TO_MAIN;
	GF_Disp_DispSelect();

	//ＶＲＡＭ転送マネージャ解放
	DeleteCellTransfer(ptr->TransferSt);
	DellVramTransferManager();

	//イベントワーク解放
	PTFrame_FreeEventWork(work);

	//特殊効果オフ
	G2_BlendNone();
	//ヒープ解放
	sys_DeleteHeap( HEAPID_PT_JUMP );
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * VRAM設定		ポケスロンでは、ポケモン表示だけで0x30000必要となる。
 * VRAM_AB(0x40000)でないとはいらん
 *
 * @param	none
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM tbl = {
		GX_VRAM_BG_64_E,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット

		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット

		GX_VRAM_OBJ_256_AB,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット

		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット

		GX_VRAM_TEX_NONE,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_NONE			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &tbl );
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL JUMP_Func_Phase1(PKTHLN_PTR work, u8 *seq)
{
	BOOL rc;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch(*seq){
	case 0:
		SetDraw(work);
		//通信同期待ちセット
		PTFrame_SetSynchroID(work, PKTLN_SYNC_ID_JMP_START_WAIT);
		(*seq)++;
		break;
	case 1:
		SetDraw(work);
		//みんな一緒にフェードインリクエスト
		WIPE_SYS_Start(	WIPE_PATTERN_FSAM, WIPE_TYPE_SHUTTERIN_DOWN,
					WIPE_TYPE_SHUTTERIN_DOWN, WIPE_FADE_BLACK,
					WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
		(*seq)++;
		break;
	case 2:
		//フェードイン待ち
		if( WIPE_SYS_EndCheck() ){
			(*seq)++;
		}
		SetDraw(work);
		break;
	case 3:	//カウント
		SetDraw(work);
		if ( PTFrame_CountDown(work) ){
			(*seq)++;
		}
		break;
	case 4:
		CommMain(work);
		if ( ControlMain(work) ){
			(*seq)++;
		}
		break;
	case 5:	//終了カウント
		if ( PTFrame_DispEnd(work) ){
			//フェードアウトリクエスト
			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
							WIPE_TYPE_FADEOUT, WIPE_FADE_BLACK,
							WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, JUMP_SEQ_PHASE2);
		}
		break;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL JUMP_Func_Phase2(PKTHLN_PTR work, u8 *seq)
{
	int point;
	int net_id;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	if (*seq == 0){
		//フェードアウト待ち
		if ( WIPE_SYS_EndCheck() ){
			*seq = 1;
		}
		return FALSE;
	}

	net_id = PTFrameGetCurrentID(work);
	//結果セット
	{
		int i;
		point = 0;
		for(i=0;i<ENTRY_MAX;i++){
			point += ptr->Poke[i].Score;
		}
		if (point > GAME_SCORE_MAX){
			point = GAME_SCORE_MAX;
		}
		OS_Printf("合計点数:%d\n",point);
		PTFrame_SetEvtResultOrg(work, net_id, point);
	}

	//親の場合はNPCの結果をここでセット
	if (net_id == COMM_PARENT_ID){
		int i,j;
		int player_num = PTFrame_GetPlayerNum(work);
		for(i=player_num;i<ENTRY_MEMBER_NUM_MAX;i++){
			point = 0;
			for(j=0;j<ENTRY_MAX;j++){
				u8 action;
				u8 jump;
				int poke_score;
				const POKE_SPEC *spec;
				spec = PTFrame_GetPokeSpec(work, i, j);
				poke_score = 0;
				jump = 0;
				if (spec->Jump){
					u8 jump;
					poke_score = NPC_SCORE_BASE+(spec->Jump*6)+(spec->Technique*2)+(spec->Stamina*2)+(gf_rand()%21);
					point += poke_score;
					jump = 30 - spec->Jump - (gf_rand()%6);
				}
				//アクションポイント加算「ジャンプ回数」
				PTFrame_AddActionPoint(	work, i, j, ADD_TYPE_JUMP, jump );
				action = gf_rand()%21;
				//アクションポイント加算「体当たり回数」
				PTFrame_AddActionPoint(	work, i, j, ADD_TYPE_ATTACK, action );
				//アクションポイント加算「失敗回数」
				PTFrame_AddActionPoint(	work, i, j, ADD_TYPE_FAIL, action );
			}
			PTFrame_SetEvtResultOrg(work, i, point);
			OS_Printf("合計点数:%d\n",point);
		}
	}
	OS_Printf("結果計算関数へ。\n");
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	BG初期化
 * @param	*ini		BGL
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void BgInit(GF_BGL_INI * ini)
{
  {	/* BG SYSTEM */
    GF_BGL_SYS_HEADER BGsys_data = {
      GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BGMODE_0, GX_BG0_AS_3D,
    };
    GF_BGL_InitBG( &BGsys_data );
  }

  //メイン
  {	/* MAIN DISP BG2 */
    GF_BGL_BGCNT_HEADER MBg2_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
      GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_M, &MBg2_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME2_M );
  }
  {	/* MAIN DISP BG1 */
    GF_BGL_BGCNT_HEADER MBg1_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x08000,
      GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_M, &MBg1_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME1_M );
  }

  {	/* MAIN DISP BG3 */
	  GF_BGL_BGCNT_HEADER MBg3_Data = {
	      0, 0, 0x800, 0,
    	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xd000, GX_BG_CHARBASE_0x04000,
		  GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
	  };
	  GF_BGL_BGControlSet( ini, GF_BGL_FRAME3_M, &MBg3_Data, GF_BGL_MODE_TEXT );
	  GF_BGL_ScrClear( ini, GF_BGL_FRAME3_M );
  }

  //サブ
  {	/* SUB DISP BG0 */
    GF_BGL_BGCNT_HEADER SBg0_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
      GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_S, &SBg0_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME0_S );
  }
  {	/* SUB DISP BG1 */
    GF_BGL_BGCNT_HEADER SBg1_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x08000,
      GX_BG_EXTPLTT_01, 2, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_S, &SBg1_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME1_S );
  }

  {	/* SUB DISP BG2 */
    GF_BGL_BGCNT_HEADER SBg2_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xd000, GX_BG_CHARBASE_0x0c000,
      GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_S, &SBg2_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME2_S );
  }

  //レコードＢＧ非表示
  GF_Disp_GX_VisibleControl( GX_PLANEMASK_BG3, VISIBLE_OFF );

}

//--------------------------------------------------------------------------------------------
/**
 * @brief	グラフィックセット
 * @param	ptr			アプリポインタ
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetGraphic(PKTHLN_JUMP_PTR ptr)
{
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_main03_NCGR,
						ptr->bgl, GF_BGL_FRAME2_M, 0, 0, FALSE, ptr->HeapID);
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_main01_NCGR,
						ptr->bgl, GF_BGL_FRAME1_M, 0, 0, FALSE, ptr->HeapID);
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub02_NCGR,
						ptr->bgl, GF_BGL_FRAME0_S, 0, 0, FALSE, ptr->HeapID);
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub03_NCGR,
						ptr->bgl, GF_BGL_FRAME1_S, 0, 0, FALSE, ptr->HeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_main03_NSCR,
						ptr->bgl, GF_BGL_FRAME2_M, 0, 0, FALSE, ptr->HeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_main01_NSCR,
						ptr->bgl, GF_BGL_FRAME1_M, 0, 0, FALSE, ptr->HeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub02_NSCR,
						ptr->bgl, GF_BGL_FRAME0_S, 0, 0, FALSE, ptr->HeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub03_NSCR,
						ptr->bgl, GF_BGL_FRAME1_S, 0, 0, FALSE, ptr->HeapID);
	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_main_NCLR,
						PALTYPE_MAIN_BG, 0, 32, ptr->HeapID );
	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub_NCLR,
						PALTYPE_SUB_BG, 0, 32*2, ptr->HeapID );

	ptr->ScoreBgArc = ArcUtil_ScrnDataGet(ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_bg_sub_point_NSCR,
						FALSE, &ptr->ScoreScrnData, ptr->HeapID);
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	コントロールメイン
 * @param	work		ポケスロンワーク
 *
 * @return	BOOL		TRUEで終了
 */
//--------------------------------------------------------------------------------------------
static BOOL ControlMain(PKTHLN_PTR work)
{
	u8 end;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);
	JUMP_CHILD_DATA *child_data;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	child_data = PKTHLN_CommPack_GetData(&data->SendData);

	ptr->PointGet = 0;

	//時間経過
#ifdef PM_DEBUG					//こっちデバッグ用
	if (!DebugPkthlnWk.TimeInfinity){
		if (ptr->Time){
			ptr->Time--;
		}
	}
#else							//こっち製品用
	if (ptr->Time){
		ptr->Time--;
	}
#endif

	//終了判定
	if (ptr->Time <= 0){
		end = 1;
	}else{
		end = 0;
	}

#ifdef PM_DEBUG
	if (sys.trg & PAD_BUTTON_X){
		end = 1;
	}
#endif

	//終了検出
	if (end){
		//ニューレコード用にレコードをセット
		int i;
		int score = 0;

		//アクター停止
		PkthlnClAct_AllAnmStop(ptr->ActCntPtr, 1);
		PokeAct_AllAnmStop(ptr->PokeActCntPtr, 1);

		for(i=0;i<ENTRY_MAX;i++){
			score += ptr->Poke[i].Score;
		}
		if (score > GAME_SCORE_MAX){
			score = GAME_SCORE_MAX;
		}
		//フレームワークにニューレコードチェック用のレコード値をセット
		PTFrame_SetCheckRecord(work, score);
		SetRecordStr(ptr, score);

		SetDraw(work);
		return TRUE;
	}

#if 0
#ifdef PM_DEBUG
	//デバッグ処理
	if ( 1 ){
		//リセット
		if ( sys.cont & PAD_BUTTON_START ){
			int i;
			for(i=0;i<JUMP_POINT_NUM;i++){
				ptr->SeetDat.TempPoint[0][i] = 0;
				ptr->SeetDat.TempPoint[1][i] = 0;
				ptr->SeetDat.TempPoint[2][i] = 0;
				ptr->SeetDat.Point[i] = 0;
				ptr->SeetDat.JPMargine[0][i] = 0;
				ptr->SeetDat.JPMargine[1][i] = 0;
				ptr->SeetDat.JPMargine[2][i] = 0;
			}
			for (i=0;i<ENTRY_MAX;i++){
				ptr->Ball[i].Speed = 0;
				ptr->Ball[i].Pos.y = 0;
				ptr->Ball[i].Fly = 0;
				ptr->Ball[i].Speed = 0;
				ptr->Ball[i].Move = 0;
				ptr->Ball[i].UpdnSpeed = 0;
				//初打ち出しフラグ立てる
				ptr->Poke[i].FirstShot = 1;
			}
		}

		if (sys.cont & PAD_BUTTON_L){
			DebugCameraInput(ptr->CameraPtr);
		}else if (sys.trg & PAD_BUTTON_X){
			//カメラ情報表示
			DebugPritnfCameraInfo(ptr->CameraPtr);
		}else if( sys.trg & PAD_KEY_LEFT ){
			debug_side--;
			if (debug_side < 0){
				debug_side = JUMP_POINT_NUM-1;
			}
			ptr->SeetDat.JumpPoint[debug_pin_no] = debug_side;
			ptr->Ball[debug_pin_no].Pos.x = ((float)debug_side/32.0 - 2.0 )*FX32_ONE;
			OS_Printf("debug_side = %d\n",debug_side);
		}else if( sys.trg & PAD_KEY_RIGHT ){
			debug_side = (debug_side+1) % JUMP_POINT_NUM;
			ptr->SeetDat.JumpPoint[debug_pin_no] = debug_side;
			ptr->Ball[debug_pin_no].Pos.x = ((float)debug_side/32.0 - 2.0 )*FX32_ONE;
			OS_Printf("debug_side = %d\n",debug_side);
		}else if (sys.trg & PAD_KEY_DOWN){
			ptr->SeetDat.TempPoint[debug_pin_no][debug_side] -= (FX32_ONE/20) ;
			OS_Printf("%d::point=%d\n",debug_side,ptr->SeetDat.Point[debug_side]);
			SetSeetPoint( debug_side, ptr->SeetDat.TempPoint[debug_pin_no][debug_side], ptr->SeetDat.TempPoint[debug_pin_no]);
		}else if (sys.trg & PAD_KEY_UP){
			ptr->SeetDat.TempPoint[debug_pin_no][debug_side] += (FX32_ONE/20) ;
			OS_Printf("%d::point=%d\n",debug_side,ptr->SeetDat.Point[debug_side]);
			SetSeetPoint( debug_side, ptr->SeetDat.TempPoint[debug_pin_no][debug_side], ptr->SeetDat.TempPoint[debug_pin_no]);
		}else if(sys.trg & PAD_BUTTON_SELECT){
			debug_pin_no = (debug_pin_no+1)%3;
		}else if(sys.trg & PAD_BUTTON_R){
			int i;
			for(i=0;i<JUMP_POINT_NUM;i++){
				OS_Printf("%d::%d,%d,%d\n",i,
						ptr->SeetDat.TempPoint[0][i],
						ptr->SeetDat.TempPoint[1][i],
						ptr->SeetDat.TempPoint[2][i]);
				OS_Printf("JM %d::%d,%d,%d\n",i,
						ptr->SeetDat.JPMargine[0][i],
						ptr->SeetDat.JPMargine[1][i],
						ptr->SeetDat.JPMargine[2][i]);
			}
			debug_stop = (debug_stop+1)%2;
		}else if(sys.trg & PAD_BUTTON_Y){
			if (ptr->Ball[0].Move){
				OS_Printf("0:まだ動作中\n");
				GF_ASSERT(0);
			}
			ptr->Ball[0].Speed = -(1.5*FX32_ONE);
			ptr->Ball[0].UpdnSpeed = -(0.5*FX32_ONE);
			ptr->Ball[0].Move = 1;
		}else if(sys.trg & PAD_BUTTON_B){
			if (ptr->Ball[1].Move){
				OS_Printf("1:まだ動作中\n");
				GF_ASSERT(0);
			}
			ptr->Ball[1].Speed = -(0.5*FX32_ONE);
			ptr->Ball[1].UpdnSpeed = -(0.5*FX32_ONE);
			ptr->Ball[1].Move = 1;
		}else if(sys.trg & PAD_BUTTON_A){
			if (ptr->Ball[2].Move){
				OS_Printf("2:まだ動作中\n");
				GF_ASSERT(0);
			}
			ptr->Ball[2].Speed = -(0.5*FX32_ONE);
			ptr->Ball[2].UpdnSpeed = -(0.5*FX32_ONE);
			ptr->Ball[2].Move = 1;
		}
	}
#endif
#endif
	//ボール移動
	MoveBallAll(work, ptr);
	//3つのテンポラリシートをマージする
	MargeSeet(&ptr->SeetDat);
	//各ボールがジャンプ動作中で無ければ、シートの位置に移動
	AdsorbBall(ptr);

	//ポケ同士のヒッチ
	HitCheck(work, ptr);

	Lmp_Generate(ptr->LampCntPtr);

	SetDraw(work);

	//子機データ収集
	child_data->PointGet = ptr->PointGet;

	return FALSE;
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	描画準備関数
 * @param	work		ポケスロンワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetDraw(PKTHLN_PTR work)
{
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);
	//描画に必要な座標セット
	SetPokemonDrawPos(work);
	//時間表示
	DispTime(ptr, ptr->Time);
	//得点表示
	DispTotalScore(ptr);

	//旗アニメーション
	FlagAnm(work);

	//ラスト３秒
	PTFrame_DispLastCount(work, ptr->Time);

	Draw3D(ptr);
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	通信データ関連メイン処理
 * @param	work		ポケスロンアプリポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CommMain(PKTHLN_PTR work)
{
	int i;
	PKTHLN_JUMP_PTR ptr;
	JUMP_CHILD_DATA *child_data;
	JUMP_PARENT_DATA *parent;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	ptr = PTFrame_GetEventWorkPtr(work);

	//タッチ検出
	if ( GF_TP_GetTrg() ){		//タッチ
		u8 touch_idx;
		//アクションポイント加算「タッチ回数」
		PTFrame_AddActionPoint(	work, PTFrameGetCurrentID(work), ENTRY_MAX, ADD_TYPE_TOUCH, 1 );
		touch_idx = CheckPokeTouch(ptr, sys.tp_x, sys.tp_y);
		if (touch_idx < JUMP_EVENT_POKE_NUM){
			//ホールドポケの決定
			ptr->HoldPoke = touch_idx;
			//タッチした座標を保存
			ptr->NowPoint.x = sys.tp_x*FX32_ONE;
			ptr->NowPoint.y = sys.tp_y*FX32_ONE+MAIN_SUB_DIST;
			ptr->NowPoint.z = 0;
		}
	}else if( GF_TP_GetCont() ){		//ベタタッチ
		if (ptr->HoldPoke < JUMP_EVENT_POKE_NUM){
			//ベタタッチカウントアップ
			if (ptr->CountTouchFrame < CONT_TOUCH_MAX){
				ptr->CountTouchFrame++;
			}else{		//ベタタッチ時間がストローク最大値を上回った場合はポケを打ち上げでしまう。
				VecFx32 stroke = {0,0,0};
				GetStrokeVec(sys.tp_x, sys.tp_y, &ptr->NowPoint, &stroke);
				//ホールドしているポケモンにストローク情報をセット
				ShotPoke(ptr, ptr->HoldPoke, &stroke);
				//ホールド解除
				ptr->HoldPoke = JUMP_EVENT_POKE_NUM;
				//ベタタッチカウントクリア
				ptr->CountTouchFrame = 0;
			}
		}
	}else{	//タッチしていない
		//ホールドポケがいるならば、ストロークベクトルを算出
		if ( (ptr->HoldPoke < JUMP_EVENT_POKE_NUM)&&(ptr->CountTouchFrame < CONT_TOUCH_MAX) ){
			VecFx32 stroke = {0,0,0};
			GetStrokeVec(sys.tp_x, sys.tp_y, &ptr->NowPoint, &stroke);
			//ホールドしているポケモンにストローク情報をセット
			ShotPoke(ptr, ptr->HoldPoke, &stroke);
		}
		//ホールド解除
		ptr->HoldPoke = JUMP_EVENT_POKE_NUM;
		//ベタタッチカウントクリア
		ptr->CountTouchFrame = 0;
	}

	//親動作
	if ( PTFrameGetCurrentID(work) == COMM_PARENT_ID ){
		u8 point_get[ENTRY_MEMBER_NUM_MAX];

		parent = PKTHLN_CommPack_GetData(&data->SendShareData);

		//親データは直接レシーバにセット
		{
			JUMP_CHILD_DATA *child;
			JUMP_CHILD_DATA *child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}

		//AI実行
#ifdef PM_DEBUG										//こっちデバッグ用
		if ( !DebugPkthlnWk.AI_Stop ){
			JumpAI_Execute(work, ptr->AICntPtr);
		}
#else												//こっち製品用
		JumpAI_Execute(work, ptr->AICntPtr);
#endif
		//プレーヤー数ループ
		for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			JUMP_CHILD_DATA *child_data;
			JUMP_POKE *jump_poke;
			child_data = PKTHLN_CommPack_GetData(&data->ReciveData[i]);

			point_get[i] = child_data->PointGet;
		}	//end for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++)

		//情報セット
		for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			parent->PointGet[i] = point_get[i];
		}
	}
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	描画準備
 * @param	work		ポケスロンアプリポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetPokemonDrawPos(PKTHLN_PTR work)
{
	int i;
	int draw_x,draw_y;
	PKTHLN_JUMP_PTR ptr = PTFrame_GetEventWorkPtr(work);

	for (i=0;i<JUMP_EVENT_POKE_NUM;i++){
		JUMP_POKE *jump_poke;
		jump_poke = &ptr->Poke[i];
		//バネシミュレーター上のボールの座標をポケモン座標に変換
		jump_poke->DispPos.y = MAIN_SUB_DIST + GROUND_BASE_OFS - (ptr->Ball[i].Pos.y * CONF_3D_TO_2D);
		jump_poke->DispPos.x = jump_poke->DispXTmp;
		//X移動制限
		if (jump_poke->DispPos.x < X_MIN*FX32_ONE){
			jump_poke->DispPos.x = X_MIN*FX32_ONE;
		}else if(jump_poke->DispPos.x > X_MAX*FX32_ONE){
			jump_poke->DispPos.x = X_MAX*FX32_ONE;
		}
		//ジャンプポイント更新
		{
			u8 point = (jump_poke->DispPos.x / FX32_ONE) / 2;
			ptr->SeetDat.JumpPoint[i] = point;
		}
		//描画座標計算
		draw_x = jump_poke->DispPos.x / FX32_ONE;
		draw_y = jump_poke->DispPos.y / FX32_ONE;
		//ポケモン位置
		PokeAct_SetPosShadow(jump_poke->PokeActPtr, draw_x, draw_y);
		//気絶アクター位置
		{
			VecFx32 mat = {0,0,0};
			const PKTHPOKE_PARAM * prm;
			mat.x = draw_x * FX32_ONE;
			mat.y = draw_y * FX32_ONE;
			//タッチタイプで汗の位置かえる
			prm = PTFrame_GetPkthlnParam(work, PTFrameGetCurrentID(work), i);
			if (prm->Cell){
				mat.y -= (24*FX32_ONE);
			}else{
				mat.y -= (16*FX32_ONE);
			}
			PkthlnClAct_SetPos(jump_poke->PanicActPtr, &mat);
		}
		if (jump_poke->PanicState){
			PkthlnClAct_SetActive(jump_poke->PanicActPtr, 1, 1);
			PokeAct_SetAnmTrns(jump_poke->PokeActPtr, ANM_TYPE_PANIC);
			//気絶SE
			if( Snd_SePlayCheckByPlayerNo(SndPlayer[i]) == FALSE ){
				Snd_SePlayEx( SE_THLON_RUNNING_OUT, SndPlayer[i] );
			}
		}else{
			PkthlnClAct_SetActive(jump_poke->PanicActPtr, 1, 0);
			PokeAct_SetAnmTrns(jump_poke->PokeActPtr, ANM_TYPE_WALK);
			if ( ptr->Ball[i].Move ){
				PokeAct_SetDir(jump_poke->PokeActPtr, POKE_DIR_UP);
			}else{
				PokeAct_SetDir(jump_poke->PokeActPtr, POKE_DIR_DOWN);
			}
		}
	}//end for

	//ヒットエフェクト
	for(i=0;i<JUMP_EVENT_POKE_NUM;i++){
		if (ptr->HitFlg[i]){
			OS_Printf("ヒットあにめ\n");
			ptr->HitFlg[i] = 0;
			PkthlnClAct_SetActive(ptr->HitActPtr[i], 1, 1);
			PkthlnClAct_SetPos(ptr->HitActPtr[i], &ptr->HitVec[i]);
			PkthlnClAct_ChgAnm(ptr->HitActPtr[i], 9);
		}
	}
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	得点取得時の旗アニメ
 * @param	work		ポケスロンアプリポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void FlagAnm(PKTHLN_PTR work)
{
	int i;
	PKTHLN_JUMP_PTR ptr;
	JUMP_PARENT_DATA *parent;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	ptr = PTFrame_GetEventWorkPtr(work);

	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		if (i == PTFrameGetCurrentID(work)){
			//通信データではなく自分のローカルデータを見る
			if (ptr->PointGet){
				//得点取得アニメ
				if (!PkthlnClAct_AnmActiveCheck(ptr->FlagActPtr[i])){
					PkthlnClAct_ChgAnm(ptr->FlagActPtr[i], 13+i);
				}
			}
		}else{
			if (parent->PointGet[i]){
				//得点取得アニメ
				if (!PkthlnClAct_AnmActiveCheck(ptr->FlagActPtr[i])){
					PkthlnClAct_ChgAnm(ptr->FlagActPtr[i], 13+i);
				}
			}
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ストロークベクトル取得
 *
 *	@param	u8 inTpX				タッチＸ座標
 *	@param	u8 inTpY				タッチＹ座標
 *	@param	VecFx32 *inNowPoint		現在ポイント
 *	@param	*outPoint				ポイント格納バッファ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void GetStrokeVec(const u8 inTpX, const u8 inTpY, const VecFx32 *inNowPoint, VecFx32 *outPoint)
{
	VecFx32 vec;
	vec.x = inTpX * FX32_ONE;
	vec.y = (inTpY * FX32_ONE) + MAIN_SUB_DIST;
	vec.z = 0;

	VEC_Subtract( &vec, inNowPoint, outPoint );

	if (outPoint->y > STROKE_MAX){
		outPoint->y = STROKE_MAX;
	}
	OS_Printf("strk_y=%x\n",outPoint->y);
}


//----------------------------------------------------------------------------
/**
 *	@brief	ポケモンをタッチしているかを判定する
 *
 *	@param	ptr			競技ワークポインタ
 *	@param	u16 inX		Ｘ座標
 *	@param	u16 inY		Ｙ座標
 *
 *	@return 	u8 	タッチしたポケインデックス	（タッチしていないときはJUMP_EVENT_POKE_NUM）
 */
//-----------------------------------------------------------------------------
static u8 CheckPokeTouch(PKTHLN_JUMP_PTR ptr, const u16 inX, const u16 inY)
{
	u8 i;
	u8 touch_list[ENTRY_MAX];
	fx32 touch_range[ENTRY_MAX];
	u8 hit_num;
	u8 target;

	fx32 now_range = PTFrame_GetPokeTouchRange()*FX32_ONE;
	hit_num =0;
	//タッチしているポケモンのリストを作成
	for (i=0;i<ENTRY_MAX;i++){
		fx32 range;
		int tx,ty;
		int x,y;
		JUMP_POKE *jump_poke;
		jump_poke = &ptr->Poke[i];

		//気絶中はタッチ不可
		if ( jump_poke->PanicState ){
			touch_list[i] = 0;
			touch_range[i] = 0;
			continue;
		}

		x = jump_poke->DispXTmp / FX32_ONE;
		y = ( GROUND_BASE_OFS - (ptr->Ball[i].Pos.y * CONF_3D_TO_2D) ) / FX32_ONE;

		PokeAct_GetTouchPosByShadowPos(jump_poke->PokeActPtr, x, y, &tx, &ty );

		if ( PTFrame_CheckTouchRange( tx, ty, inX, inY, PTFrame_GetPokeTouchRange(), &range) ){
			//タッチ
			touch_range[i] = range;
			touch_list[i] = 1;
			hit_num++;
		}else{
			touch_range[i] = 0;
			touch_list[i] = 0;
		}
	}

	if (hit_num == 0){
		return JUMP_EVENT_POKE_NUM;		//タッチ範囲外
	}

	target = ENTRY_MAX;
	for (i=0;i<ENTRY_MAX;i++){
		if (touch_list[i]){
			if (touch_range[i] < now_range){
				target = i;
				now_range = touch_range[i];
			}
		}
	}
	if (target==ENTRY_MAX){
		GF_ASSERT(0);
		return JUMP_EVENT_POKE_NUM;
	}

	return target;

#if 0
	for(i=0;i<ENTRY_MAX;i++){
		u8 j;
		BOOL rc;
		VecFx32 dir_vec;
		fx32 len;
		int tx,ty;
		int x,y;
		JUMP_POKE *jump_poke;
		jump_poke = &ptr->Poke[i];

		//気絶中はタッチ不可
		if ( jump_poke->PanicState ){
			continue;
		}
		//他のポケと重なっていてもタッチ不可
		for (j=0;j<ENTRY_MAX;j++){
			if (jump_poke->Hit[j]){
				continue;
			}
		}

		x = jump_poke->DispXTmp / FX32_ONE;
		y = ( MAIN_SUB_DIST + GROUND_BASE_OFS - (ptr->Ball[i].Pos.y * CONF_3D_TO_2D) ) / FX32_ONE;

		PokeAct_GetTouchPosByShadowPos(jump_poke->PokeActPtr, x, y, &tx, &ty );
		rc = PokeAct_CheckTouch(jump_poke->PokeActPtr, tx*FX32_ONE, ty*FX32_ONE,
								inX, inY+(MAIN_SUB_DIST/FX32_ONE));

		//射程と比較
		if (rc){
			//タッチしている
			OS_Printf("%dのポケにタッチ\n",i);
			return (i);
		}
	}
	return JUMP_EVENT_POKE_NUM;
#endif
}

//----------------------------------------------------------------------------
/**
 *	@brief	円同士の当たり判定
 *
 *	@param	inVec1		対象位置ベクトル
 *	@param	inRange1	半径
 *	@param	inVec2		対象位置ベクトル
 *	@param	inRange2	半径
 *
 *	@return 	BOOL 	TRUE:ヒット	FALSE:ノーヒット
 */
//-----------------------------------------------------------------------------
static BOOL CheckCircle(const VecFx32 *inVec1, const fx32 inRange1,
		const VecFx32 *inVec2, const fx32 inRange2)
{
	fx32 len;
	VecFx32 vec;
	VEC_Subtract( inVec1, inVec2, &vec );

	//方向ベクトルの長さを取得
	len = VEC_Mag(&vec);

	if (len <= inRange1+inRange2){
		return TRUE;
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモンの打ち上げ
 *
 *	@param	ptr				競技ポインタ
 *	@param	inIdx			ポケモンインデックス
 *	@param	inStroke		ストロークベクトル
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void ShotPoke(PKTHLN_JUMP_PTR ptr, const u8 inIdx, const VecFx32 *inStroke)
{
	fx32 y_val, x_val;
	BALL *ball;


	//上向きストロークは無効
	if (inStroke->y <= 0){
		return;
	}

	ball = &ptr->Ball[inIdx];

	if (ball->Move){
		OS_Printf("%d:まだ動作中\n",inIdx);
		return;
	}
	//ストローク値をスピードに変換
	y_val = (inStroke->y/CONF_3D_TO_2D);
	OS_Printf("byval = %x\n",y_val);
	y_val /= 2.5;
	OS_Printf("ayval = %x\n",y_val);

	x_val = -inStroke->x;
	x_val/=SIDE_SP_CONF;
	if (x_val>=0){
		if (x_val > SIDE_SPEED_MAX*FX32_ONE){
			x_val = SIDE_SPEED_MAX*FX32_ONE;
		}
	}else{
		if (x_val < -(SIDE_SPEED_MAX*FX32_ONE)){
			x_val = -(SIDE_SPEED_MAX*FX32_ONE);
		}
	}
	OS_Printf("xval = %x\n",x_val);
	ptr->Poke[inIdx].DispXSpd = (x_val);
	//各ポケモンのパラメータ反映
	ptr->Poke[inIdx].DispXSpd = (ptr->Poke[inIdx].DispXSpd * ptr->Poke[inIdx].Step) / STEP_DIV_CONF;

	ball->Speed = -y_val;
	ball->UpdnSpeed = -y_val;
	ball->Move = 1;
	//ペンはなしたSE
	Snd_SePlayEx( SE_JUMP_TOUCH, SndPlayer[inIdx] );
}

/////////////////////////////////////////////////////////////////////////////////////

//----------------------------------------------------------------------------
/**
 *	@brief	3Dの設定
 *
 *	@param		ptr		競技ポインタ
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void Setup3D(PKTHLN_JUMP_PTR ptr)
{
	// NitroSystem:３Ｄエンジンの初期化
	NNS_G3dInit();
	// マトリクススタックの初期化
    G3X_InitMtxStack();

	// ジオメトリエンジン起動後必ず呼ばれなければならない
    G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);

	{
	// ３Ｄ使用面の設定(表示＆プライオリティー)
    G2_SetBG0Priority(2);

	// 各種描画モードの設定(シェード＆アンチエイリアス＆半透明)
    G3X_SetShading( GX_SHADING_TOON );
    G3X_AntiAlias( FALSE );
	G3X_AlphaTest( FALSE, 0 );	// アルファテスト　　オフ
	G3X_AlphaBlend( FALSE );		// アルファブレンド　オン
	G3X_EdgeMarking( FALSE );
///	G3X_SetFog( FALSE, GX_FOGBLEND_COLOR_ALPHA, GX_FOGSLOPE_0x8000, 0 );

	// クリアカラーの設定
    G3X_SetClearColor(GX_RGB(0,0,0),0,0x7fff,63,FALSE);	//color,alpha,depth,polygonID,fog

	// ビューポートの設定
    G3_ViewPort(0, 0, 255, 191);
	}

	ptr->CameraPtr = GFC_AllocCamera( ptr->HeapID );
	InitCamera( ptr );
}

//----------------------------------------------------------------------------
/**
 *	@brief	床の描画
 *
 *	@param		ptr		競技ポインタ
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void DrawSeet(PKTHLN_JUMP_PTR ptr)
{
	int i;

	{
		VecFx32		scal = { FX32_ONE, FX32_ONE,FX32_ONE };

		// 座標変換
///		NNS_G3dGeTranslateVec( &inData->Pos );			// 平行移動
		NNS_G3dGeScaleVec(&scal);								// 拡縮


		// ポリゴンアトリビュート設定
		NNS_G3dGePolygonAttr(
				   GX_LIGHTMASK_0,			  // ライトを反映しない
				   GX_POLYGONMODE_MODULATE,	  // モジュレーションポリゴンモード
				   GX_CULL_BACK,             // カリング
				   //GX_CULL_NONE,             // カリング
				   0,                         // ポリゴンＩＤ ０
				   0x31,					  // アルファ値
				   GX_POLYGON_ATTR_MISC_NONE );

		NNS_G3dGeColor( GX_RGB( 31, 5, 0 ) );

		//グローバル状態を反映
		NNS_G3dGlbFlush();

		// 四角形を描画開始
		NNS_G3dGeBegin( GX_BEGIN_QUAD_STRIP );
		{
			// 色を変えるよう
			static int count1 = 0;
			static int count2 = 10;
			static int count3 = 20;

			count1 = 0;
			count2 = 10;
			count3 = 20;


			NNS_G3dGeVtx( -FX32_ONE*2,  0, 0 );
			NNS_G3dGeVtx( -FX32_ONE*2,  BALL_Y_MIN_LIMIT, 0 );

			for(i=1;i<=JUMP_POINT_NUM;i++){
				float n, val;
				n = (float)i;
				val = ((n-64.0) * 4.0)/128.0;
				// 頂点
				NNS_G3dGeVtx(  val*FX32_ONE,  ptr->SeetDat.Point[i-1], 0 );
				NNS_G3dGeVtx(  val*FX32_ONE,  BALL_Y_MIN_LIMIT, 0 );

				// 色
				NNS_G3dGeColor( GX_RGB( count1 , count2 , count3  ) );

				// 各色の要素を変動させる
				count1 = (count1 + 1) % 31;
				count2 = (count2 + 1) % 31;
				count3 = (count3 + 1) % 31;
			}
			{
				float val;
				val = ((129.0-64.0) * 4.0)/128.0;
				NNS_G3dGeVtx( -FX32_ONE*2,  0, 0 );
				NNS_G3dGeVtx( -FX32_ONE*2,  BALL_Y_MIN_LIMIT, 0 );
			}
		}
		// 描画終了
		NNS_G3dGeEnd();
#ifdef DEBUG_3D
		//ボール描画
		NNS_G3dGeBegin( GX_BEGIN_QUADS );
		for(i=0;i<ENTRY_MAX;i++){
			if (i == 0){
				NNS_G3dGeColor( GX_RGB( 31, 0, 0 ) );
			}else if(i==1){
				NNS_G3dGeColor( GX_RGB( 0, 31, 0 ) );
			}else{
				NNS_G3dGeColor( GX_RGB( 0, 0, 31 ) );
			}

			NNS_G3dGeVtx(  ptr->Ball[i].Pos.x - (0.1*FX32_ONE),  ptr->Ball[i].Pos.y + (0.1*FX32_ONE), FX32_ONE );
			NNS_G3dGeVtx(  ptr->Ball[i].Pos.x - (0.1*FX32_ONE),  ptr->Ball[i].Pos.y - (0.1*FX32_ONE), FX32_ONE );
			NNS_G3dGeVtx(  ptr->Ball[i].Pos.x + (0.1*FX32_ONE),  ptr->Ball[i].Pos.y - (0.1*FX32_ONE), FX32_ONE );
			NNS_G3dGeVtx(  ptr->Ball[i].Pos.x + (0.1*FX32_ONE),  ptr->Ball[i].Pos.y + (0.1*FX32_ONE), FX32_ONE );
		}
		// 描画終了
		NNS_G3dGeEnd();
#endif	//DEBUG_3D
	}
///	NNS_G3dGlbFlush();
}

//----------------------------------------------------------------------------
/**
 *	@brief	3Dの表示
 *
 *	@param		ptr		競技ポインタ
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void Draw3D(PKTHLN_JUMP_PTR ptr)
{
	//３Ｄ描画開始
	GF_G3X_Reset();
	// カメラ設定
	GFC_CameraLookAt();

	DrawSeet(ptr);
	/* ジオメトリ＆レンダリングエンジン関連メモリのスワップ */
	GF_G3_RequestSwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_Z);
}

//----------------------------------------------------------------------------
/**
 *	@brief	カメラ作成＆初期化
 *
 *	@param	ptr			競技ポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void InitCamera( PKTHLN_JUMP_PTR ptr )
{
	// 初期化
	{
		CAMERA_ANGLE angle;
		VecFx32 up;
		VecFx32 shift_vec = { 0, CAMERA_SHIFT_Y, CAMERA_SHIFT_Z };

		ptr->CameraTarget.x = 0;
		ptr->CameraTarget.y = 0;
		ptr->CameraTarget.z = 0;

		angle.x = 0;
		angle.y = 0;
		angle.z = 0;


		GFC_InitCameraTDA(
				&ptr->CameraTarget, CAMERA_DISTANCE,
				&angle, CAMERA_PERS,
				GF_CAMERA_ORTHO,
				TRUE,
				ptr->CameraPtr
				);
		GFC_ShiftCamera(&shift_vec, ptr->CameraPtr);
		GFC_SetCameraClip(4*FX32_ONE,256*FX32_ONE, ptr->CameraPtr);

		up.x = 0;
		up.y = FX32_ONE;
		up.z = 0;
		GFC_SetCamUp( &up, ptr->CameraPtr );

		GFC_AttachCamera( ptr->CameraPtr );
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	シートのマージ
 *
 *	@param	seet		シートポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MargeSeet(SEET_DAT *seet)
{
	int i;
	//ジャンプポイント間の補間を行う
	Fix(seet, 0, 0, 1);		//インデックス0-1の補間
	Fix(seet, 1, 1, 2);		//インデックス1-2の補間
	Fix(seet, 2, 2, 0);		//インデックス2-0の補間
	for(i=0;i<JUMP_POINT_NUM;i++){
		seet->Point[i] = seet->TempPoint[0][i];
		if (seet->Point[i] > seet->TempPoint[1][i]){
			seet->Point[i] = seet->TempPoint[1][i];
		}
		if (seet->Point[i] > seet->TempPoint[2][i]){
			seet->Point[i] = seet->TempPoint[2][i];
		}
		if (seet->Point[i] > seet->JPMargine[0][i]){
			seet->Point[i] = seet->JPMargine[0][i];
		}
		if (seet->Point[i] > seet->JPMargine[1][i]){
			seet->Point[i] = seet->JPMargine[1][i];
		}
		if (seet->Point[i] > seet->JPMargine[2][i]){
			seet->Point[i] = seet->JPMargine[2][i];
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	シートのマージ
 *
 *	@param	seet		シートのマージ
 *	@param	inMargeFlg	どのシートをマージするかのビット
 *	@param	outPoint	マージ結果
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MargeSeetEx(SEET_DAT *seet, const u8 inMargeFlg, fx32 *outPoint)
{
	int i;
	for(i=0;i<JUMP_POINT_NUM;i++){
		outPoint[i] = 0;
		if (inMargeFlg & MARGE_1){
			if (outPoint[i] > seet->TempPoint[0][i]){
				outPoint[i] = seet->TempPoint[0][i];
			}
			if (outPoint[i] > seet->JPMargine[0][i]){
				outPoint[i] = seet->JPMargine[0][i];
			}
		}
		if (inMargeFlg & MARGE_2){
			if (outPoint[i] > seet->TempPoint[1][i]){
				outPoint[i] = seet->TempPoint[1][i];
			}
			if (outPoint[i] > seet->JPMargine[1][i]){
				outPoint[i] = seet->JPMargine[1][i];
			}
		}
		if (inMargeFlg & MARGE_3){
			if (outPoint[i] > seet->TempPoint[2][i]){
				outPoint[i] = seet->TempPoint[2][i];
			}
			if (outPoint[i] > seet->JPMargine[2][i]){
				outPoint[i] = seet->JPMargine[2][i];
			}
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ジャンプポイント間の線形補間
 *
 *	@param	seet		シート
 *	@param	inIdx		補間シートインデックス
 *	@param	inTmp1		ジャンプポイント1
 *	@param	inTmp2		ジャンプポイント2
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void Fix(SEET_DAT *seet, const u8 inIdx, const u8 inTmp1, const u8 inTmp2)
{
	int i;
	int num;
	int *point1;
	int *point2;
	const u8 *idx1;
	const u8 *idx2;
	fx32 dif;
	fx32 base_y;
	//X座標の小さい方を基点にする
	{
		int x_pos1,x_pos2;
		x_pos1 = seet->JumpPoint[inTmp1];
		x_pos2 = seet->JumpPoint[inTmp2];

		if ( x_pos1 <= x_pos2 ){
			point1 = &seet->JumpPoint[inTmp1];
			point2 = &seet->JumpPoint[inTmp2];
			idx1 = &inTmp1;
			idx2 = &inTmp2;
		}else{
			point1 = &seet->JumpPoint[inTmp2];
			point2 = &seet->JumpPoint[inTmp1];
			idx1 = &inTmp2;
			idx2 = &inTmp1;
		}
	}

	//配列クリア
	for(i=0;i<JUMP_POINT_NUM;i++){
		seet->JPMargine[inIdx][i] = 0;
	}

	//２点のY差分を計算
	base_y = seet->TempPoint[*idx1][*point1];
	dif = seet->TempPoint[*idx2][*point2] - seet->TempPoint[*idx1][*point1];
	num = (*point2) - (*point1);
	//２点のX距離分ループ
	for(i=0;i<num-1;i++){
		int base = (*point1) + i+1;
		seet->JPMargine[inIdx][base] = base_y + ( dif*(i+1) ) / num;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポイント加算
 *
 *	@param	poke		ジャンプポケモン
 *
 *	@return	u8			コンボ数（1〜COMBO_MAX）
 */
//-----------------------------------------------------------------------------
static u8 CalcPoint(JUMP_POKE *poke)
{
	//連鎖数加算
	if (poke->Combo < COMBO_MAX){
		poke->Combo++;
	}

	//得点反映
	poke->Score += poke->Combo;
	if (poke->Score > GAME_SCORE_MAX){
		poke->Score = GAME_SCORE_MAX;
	}

	return poke->Combo;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボールシミュレータの動作
 *
 *	@param	work	ポケスロンワーク
 *	@param	ptr		管理ポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MoveBallAll(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr)
{
	int i, j;
	u8 my_net_id;

	my_net_id = PTFrameGetCurrentID(work);

	for(i=0;i<ENTRY_MAX;i++){
#if 0
#ifdef PM_DEBUG
		if (debug_stop){
			if (i==2){
				continue;
			}
		}
#endif
#endif
		MoveBall(work, ptr, i);
	}

	//ランプとのあたり
	for(i=0;i<ENTRY_MAX;i++){
		int range;
		fx32 x,y;
		int tx,ty;
		VecFx32 poke_vec;
		int sx, sy;
		POKE_ACT_PTR poke_ptr;
#if 0	//仕様変更	気絶中でもポイント取得可能
		if (ptr->Poke[i].PanicState){
			continue;
		}
#endif

		poke_ptr = ptr->Poke[i].PokeActPtr;
		sx = ptr->Poke[i].DispXTmp / FX32_ONE;
		sy = ( MAIN_SUB_DIST + GROUND_BASE_OFS - (ptr->Ball[i].Pos.y * CONF_3D_TO_2D) ) / FX32_ONE;
		PokeAct_GetTouchPosByShadowPos(	poke_ptr, sx, sy, &tx, &ty);
		PokeAct_GetHitData(poke_ptr, tx*FX32_ONE, ty*FX32_ONE, &poke_vec.x, &poke_vec.y, &range);
		poke_vec.z = 0;
		for(j=0;j<LAMP_NUM;j++){
			BOOL rc;
			const VecFx32 *vec;

			if ( !Lmp_IsValid(ptr->LampCntPtr, j) ){
				continue;
			}
			vec = Lmp_GetPos(ptr->LampCntPtr, j);
			rc = CheckCircle(&poke_vec, range * FX32_ONE,
					vec, LAMP_RANGE);
			if (rc){
				u8 combo;
				//ランプ消灯
				Lmp_Vanish(ptr->LampCntPtr, j);
				//ポケの得点加算
				combo = CalcPoint(&ptr->Poke[i]);
				//ポイント表示
				Lmp_DispPoint(ptr->LampCntPtr, j, combo);
				//ポイント取得フラグ
				ptr->PointGet = 1;
				//得点取得SE
				Snd_SePlayEx( SE_JUMP_LAMP_GET, SndPlayer[i] );
				//ピッチ変更
				Snd_PlayerSetTrackPitchByPlayerNo( SndPlayer[i], SND_TRACK_BITMASK, SndPitch[combo-1] );
				//アクションポイント加算「得点取得回数」
				PTFrame_AddActionPoint(	work, my_net_id, i, ADD_TYPE_GET, 1 );
			}
		}
	}

	//気絶時間デクリメント
	for(i=0;i<ENTRY_MAX;i++){
		if (ptr->Poke[i].PanicState ){
			ptr->Poke[i].PanicCount--;
			if (ptr->Poke[i].PanicCount <= 0){
				ptr->Poke[i].PanicCount = 0;
				ptr->Poke[i].PanicState = 0;
			}
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボールシミュレータの動作
 *
 *	@param	work	ポケスロンワーク
 *	@param	ptr		管理ポインタ
 *	@param	inIdx	対象インデックス
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MoveBall(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr, const u8 inIdx)
{
	BALL *ball;
	int pos;
	u8 mask;
	fx32 seet[JUMP_POINT_NUM];
	u8 my_net_id;

	ball = &ptr->Ball[inIdx];

	//ジャンプ動作していないなら処理を行わない
	if (!ball->Move){
		return;
	}

	my_net_id = PTFrameGetCurrentID(work);

	pos = ptr->SeetDat.JumpPoint[inIdx];

	switch(inIdx){
	case 0:
		mask = (MARGE_2|MARGE_3);
		break;
	case 1:
		mask = (MARGE_1|MARGE_3);
		break;
	case 2:
		mask = (MARGE_1|MARGE_2);
		break;
	default:
		GF_ASSERT(0);
		return ;
	}

	MargeSeetEx(&ptr->SeetDat, mask, seet);

	if (ball->Fly){
		//打ち上げ速度はマイナスにはならないはず
		if (ball->UpdnSpeed <= 0){
			OS_Printf("打ち上げ速度がプラスではない %x\n",ball->UpdnSpeed);
			GF_ASSERT(0);
			ball->Fly = 0;
			ball->Pos.y = seet[pos];
			ball->UpdnSpeed = 0;
			ball->Move = 0;
			ball->Speed = 0;
			ptr->Poke[inIdx].FirstShot = 1;
			//シート位置を自然長の位置へ
			SetTmpPoint(ptr, inIdx, pos, 0);
			return ;
		}
		//ボールの座標更新
		ball->Pos.y += ball->Speed;
		if (ptr->Poke[inIdx].DispXSpd != 0){	//横移動
			MoveSide(&ptr->Poke[inIdx], ball);
		}

		if (ball->Pos.y > seet[pos]){
			ball->Speed -= GRAVITY;
			//打ち出したときのスピードより大きくならない
			if (ball->Speed * (-1) > ball->UpdnSpeed){
				ball->Speed =  ball->UpdnSpeed * (-1);
			}
		}else if (ball->Pos.y <= seet[pos]){	//地上到達チェック
			//スピードが0になったら
			if (ball->Speed == 0){
				ball->Fly = 0;
				ball->Pos.y = seet[pos];
				ball->UpdnSpeed = 0;
				ball->Move = 0;
				//シート位置を自然長の位置へ
				SetTmpPoint(ptr, inIdx, pos, 0);
			}else if(ball->Speed < 0){
				ball->Fly = 0;
				//横移動減速
				DecSideSpeed(&ptr->Poke[inIdx]);

				//接地速度が余りに遅いと、シートのせり上がりまで時間がかかるので、
				//一定速度に満たなかった場合は速度補正する
				if (ball->Speed > -GRAVITY){
					OS_Printf("落下速度そんなにない\n");
					ball->Speed = -GRAVITY;
				}
				//シート設置スピードの記憶
				ball->UpdnSpeed = ball->Speed;
				OS_Printf("down_speed = %x\n",ball->Speed);
#if 0
				//シートへの飛び込み速度が、反発スピードより小さい場合は,
				//ストップする
				if (ball->UpdnSpeed*(-1)<DEC_SPEED){
					//シートに吸着
					ball->Fly = 0;
					ball->Pos.y = seet[pos];
					ball->UpdnSpeed = 0;
					ball->Move = 0;
				}
#endif
			}else{
				OS_Printf("シートが上に移動\n");
				//シートに吸着
				ball->Fly = 0;
				ball->Pos.y = seet[pos];
				ball->UpdnSpeed = 0;
				ball->Move = 0;
				ball->Speed = 0;
				//シート位置を自然長の位置へ
				SetTmpPoint(ptr, inIdx, pos, 0);
			}
		}
	}else{// if (ball->Fly)
#ifdef PM_DEBUG
		D_Print(0==inIdx, "pos=%x speed=%x seet=%x udsp=%x\n",ball->Pos.y, ball->Speed, seet[pos], ball->UpdnSpeed);
#endif
		GF_ASSERT(ball->UpdnSpeed <= 0);
		{
			//ボールの座標更新
			ball->Pos.y += ball->Speed;

			//限界位置設定
			if (ball->Pos.y < BALL_Y_MIN_LIMIT){
				ball->Pos.y = BALL_Y_MIN_LIMIT;
				ball->Speed = 0;	//もうこれ以上、下に沈み込まないから、スピードを失わせる
			}
			//シートから離れたら
			if (ball->Pos.y >= seet[pos]){
#ifdef PM_DEBUG
				debug_count1 = 0;
				debug_count2 = 0;
#endif
				//シート位置を自然長の位置へ
				SetTmpPoint(ptr, inIdx, pos, 0);

				//初打ち出し時は各ポケモンのパラメータを反映
				if (ptr->Poke[inIdx].FirstShot){
					ball->Speed = (ball->Speed * ptr->Poke[inIdx].Jump) / JUMP_DIV_CONF;
					OS_Printf("speed = %d\n",ball->Speed);
				}

				if (ball->Speed >JUMP_SPEED_MAX){
					ball->Speed = JUMP_SPEED_MAX;
				}

				//ここでスピードを減速させる（0.9倍処理）
				OS_Printf("bfsp=%x\n",ball->Speed);
				ball->Speed = (ball->Speed * 9) /10;
				OS_Printf("afsp=%x\n",ball->Speed);

				//スピード0になったら
				if (ball->Speed == 0){
					//初打ち出しがスピード0の場合
					if (ptr->Poke[inIdx].FirstShot){
						Snd_SePlayEx( SE_PKTH_JUMP_FAILED, SndPlayer[HIT_SE_IDX] );	//PLAYER固定
					}
					ball->Fly = 0;
					ball->Pos.y = seet[pos];
					ball->UpdnSpeed = 0;
					ball->Move = 0;
					//シート位置を自然長の位置へ
					SetTmpPoint(ptr, inIdx, pos, 0);
				}else if(ball->Speed > 0){
					if( (ball->Speed <= GRAVITY*11)&&(!ptr->Poke[inIdx].FirstShot) ){
						//打ち上げ速度が重力加速度の11倍以下の場合は打ち出せない(初打ち出しは除く)
						ball->Fly = 0;
						ball->Pos.y = seet[pos];
						ball->UpdnSpeed = 0;
						ball->Speed = 0;
						ball->Move = 0;
						//シート位置を自然長の位置へ
						SetTmpPoint(ptr, inIdx, pos, 0);
					}else{
						ball->Fly = 1;
						//打ち出しスピードの記憶
						ball->UpdnSpeed = ball->Speed;
						OS_Printf("up_speed = %x\n",ball->Speed);
						//初打ち出しフラグ落とす
						ptr->Poke[inIdx].FirstShot = 0;
						//打ち出しSE
						Snd_SePlayEx( SE_JUMP_UP, SndPlayer[HIT_SE_IDX] );	//PLAYER固定に変更
						//アクションポイント加算「ジャンプ」
						PTFrame_AddActionPoint(	work, my_net_id, inIdx, ADD_TYPE_JUMP, 1 );
					}
				}else{
					OS_Printf("シートが下に移動\n");
				}
			}else if (ball->Pos.y < seet[pos]){
				OS_Printf("posy=%x,seet[pos]=%x", ball->Pos.y, seet[pos]);
				if (ball->Speed < 0){
					ball->Speed += DEC_SPEED;
					if (ball->Speed >= 0){
						ball->Speed = 0;
					}
#ifdef PM_DEBUG
					debug_count1++;
					OS_Printf("減速回数%d, speed=%x\n",debug_count1, ball->Speed);
#endif
				}else if (ball->Speed >= 0){
					ball->Speed += ADD_SPEED;
#ifdef PM_DEBUG
					debug_count2++;
					OS_Printf("加速回数%d, speed=%x\n",debug_count2, ball->Speed);
#endif
					//設置速度はプラスにはならないはず
					if (ball->UpdnSpeed >= 0){
						OS_Printf("設置速度がマイナスではない %x\n",ball->UpdnSpeed);
						GF_ASSERT(0);
						ball->Fly = 0;
						ball->Pos.y = seet[pos];
						ball->UpdnSpeed = 0;
						ball->Move = 0;
						ball->Speed = 0;
						//シート位置を自然長の位置へ
						SetTmpPoint(ptr, inIdx, pos, 0);
						return ;
					}
					//シート設置速度よりも打ち出し速度は速くならない
					if (ball->Speed > ball->UpdnSpeed*(-1)){
						ball->Speed = ball->UpdnSpeed*(-1);
					}
				}
			}
		}
	}

	//連鎖数クリア
	if ( (!ball->Fly)||(!ball->Move)||(ball->Speed==0) ){
		ptr->Poke[inIdx].Combo = 0;
	}

	//ボールとシートくっついてる
	if ( (!ball->Fly)&&(ball->Move) ){
		SetTmpPoint(ptr, inIdx, pos, ball->Pos.y);
	}

	//初打ち出しフラグ立てる
	if (!ball->Move){
		ptr->Poke[inIdx].FirstShot = 1;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	横移動
 *
 *	@param	poke		ジャンプポケモン
 *	@param	ball		シミュレート用ボールポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MoveSide(JUMP_POKE *poke, const BALL *ball)
{
	//0より大きくないと横移動不可
	if (ball->Pos.y <= 0){
		return ;
	}

	poke->DispXTmp = poke->DispPos.x + poke->DispXSpd;
	//X移動制限
	if (poke->DispXTmp < X_MIN*FX32_ONE){
		poke->DispXTmp = X_MIN*FX32_ONE;
	}else if(poke->DispXTmp > X_MAX*FX32_ONE){
		poke->DispXTmp = X_MAX*FX32_ONE;
	}
}

#ifdef PM_DEBUG
static void DebugCameraInput(GF_CAMERA_PTR camera_ptr)
{
	u8 view;
	fx32 dist;
	u16 persp_way;

	CAMERA_ANGLE angle = {0,0,0,0};
	VecFx32 move = {0,0,0};

	if (1){
/**
		if (sys.cont & PAD_BUTTON_B){			//カメラ回転（公転）
			if (sys.cont & PAD_KEY_UP){
				angle.x = ANGLE_MOVE;
				GFC_AddCameraAngleRev(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_DOWN){
				angle.x = -ANGLE_MOVE;
				GFC_AddCameraAngleRev(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_LEFT){
				angle.y = -ANGLE_MOVE;
				GFC_AddCameraAngleRev(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_RIGHT){
				angle.y = ANGLE_MOVE;
				GFC_AddCameraAngleRev(&angle,camera_ptr);
			}
		}
		else if (sys.cont & PAD_BUTTON_Y){		//カメラ回転（自転）
			if (sys.cont & PAD_KEY_UP){
				angle.x = ANGLE_MOVE;
				GFC_AddCameraAngleRot(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_DOWN){
				angle.x = -ANGLE_MOVE;
				GFC_AddCameraAngleRot(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_LEFT){
				angle.y = ANGLE_MOVE;
				GFC_AddCameraAngleRot(&angle,camera_ptr);
			}else if (sys.cont & PAD_KEY_RIGHT){
				angle.y = -ANGLE_MOVE;
				GFC_AddCameraAngleRot(&angle,camera_ptr);
			}
		}
*/
		if (sys.cont & PAD_BUTTON_A){
			if (sys.cont & PAD_KEY_UP){			//カメラズームアウト
				persp_way = GFC_GetCameraPerspWay(camera_ptr);
				if (persp_way+16<0x4000){
					GFC_AddCameraPerspWay(64,camera_ptr);
				}
			}else if (sys.cont & PAD_KEY_DOWN){	//カメラズームイン
				persp_way = GFC_GetCameraPerspWay(camera_ptr);
				if ((u16)(persp_way-16)>0x0000){
					GFC_AddCameraPerspWay(-64,camera_ptr);
				}
			}else if (sys.cont & PAD_KEY_LEFT){
				GFC_AddCameraPerspWay(64,camera_ptr);
				persp_way = GFC_GetCameraPerspWay(camera_ptr);
				//カメラの中心にある2D画像が、崩れずに表示できる距離を求める
				//つぶれずに表示するためには、1Dot　＝　1Unitで計算すればよい
				//カメラが画面中心を見つめるとき、画面半分のサイズは、96Dot
				//表示させたい、カメラのパースを考え、96Dot　＝　96Unitになる距離にすればよい
				dist = FX_Div( FX_Mul( FX_CosIdx( persp_way ), FX_F32_TO_FX32(96) ),
									 FX_SinIdx( persp_way ));
				GFC_SetCameraDistance(dist,camera_ptr);
			}else if(sys.cont & PAD_KEY_RIGHT){
				GFC_AddCameraPerspWay(-64,camera_ptr);
				persp_way = GFC_GetCameraPerspWay(camera_ptr);
				//カメラの中心にある2D画像が、崩れずに表示できる距離を求める
				//つぶれずに表示するためには、1Dot　＝　1Unitで計算すればよい
				//カメラが画面中心を見つめるとき、画面半分のサイズは、96Dot
				//表示させたい、カメラのパースを考え、96Dot　＝　96Unitになる距離にすればよい
				dist = FX_Div( FX_Mul( FX_CosIdx( persp_way ), FX_F32_TO_FX32(96) ),
									 FX_SinIdx( persp_way ));
				GFC_SetCameraDistance(dist,camera_ptr);
			}
		}
		else if (sys.cont & PAD_BUTTON_X){
			fx32 shift;
			if(sys.cont & PAD_BUTTON_R){
				shift = (FX32_ONE*1)/10;
			}else{
				shift = FX32_ONE;
			}
			if (sys.cont & PAD_KEY_UP){
				move.y -= shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}else if (sys.cont & PAD_KEY_DOWN){
				move.y += shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}else if (sys.cont & PAD_KEY_LEFT){
				move.x -= shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}else if (sys.cont & PAD_KEY_RIGHT){
				move.x += shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}
		}else if (sys.cont & PAD_BUTTON_START){
			fx32 shift;
			if(sys.cont & PAD_BUTTON_R){
				shift = (FX32_ONE*1)/10;
			}else{
				shift = FX32_ONE;
			}
			if (sys.cont & PAD_KEY_UP){
				move.y += shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}else if (sys.cont & PAD_KEY_DOWN){
				move.y -= shift;
				GFC_ShiftCamera(&move,camera_ptr);
			}
		}else if(sys.cont & PAD_BUTTON_R){
			fx32 near,far;
			if (sys.cont & PAD_KEY_UP){
				far = GFC_GetCameraFar(camera_ptr);
				near = GFC_GetCameraNear(camera_ptr);
				far += FX32_ONE;
				OS_Printf("far=%d\n",far/FX32_ONE);
				GFC_SetCameraClip(near,far,camera_ptr);
			}else if (sys.cont & PAD_KEY_DOWN){
				far = GFC_GetCameraFar(camera_ptr);
				near = GFC_GetCameraNear(camera_ptr);
				far -= FX32_ONE;
				OS_Printf("far=%d\n",far/FX32_ONE);
				GFC_SetCameraClip(near,far,camera_ptr);
			}else if(sys.cont & PAD_KEY_RIGHT){
				far = GFC_GetCameraFar(camera_ptr);
				near = GFC_GetCameraNear(camera_ptr);
				near += FX32_ONE;
				OS_Printf("near=%d\n",near/FX32_ONE);
				GFC_SetCameraClip(near,far,camera_ptr);
			}else if(sys.cont & PAD_KEY_LEFT){
				far = GFC_GetCameraFar(camera_ptr);
				near = GFC_GetCameraNear(camera_ptr);
				near -= FX32_ONE;
				OS_Printf("near=%d\n",near/FX32_ONE);
				GFC_SetCameraClip(near,far,camera_ptr);
			}
		}
		else if (sys.cont & PAD_KEY_UP){	//カメラを遠ざける
			GFC_AddCameraDistance(FX32_ONE,camera_ptr);
		}else if (sys.cont & PAD_KEY_DOWN){	//カメラを近づける
			GFC_AddCameraDistance(-FX32_ONE,camera_ptr);
		}
	}
}
static void DebugPritnfCameraInfo(GF_CAMERA_PTR camera_ptr)
{
	CAMERA_ANGLE angle;
	u16 angle_x;

	angle = GFC_GetCameraAngle(camera_ptr);
	//仰角⇒地面からの傾きに変換
	angle_x = -angle.x;

	OS_Printf("距離：%x\n",GFC_GetCameraDistance(camera_ptr));
	OS_Printf("アングル：%x\n",angle.x);
	OS_Printf("パース：%x\n",GFC_GetCameraPerspWay(camera_ptr));
	OS_Printf("ニア・ファー：%d_%d\n",
			GFC_GetCameraNear(camera_ptr)/FX32_ONE, GFC_GetCameraFar(camera_ptr)/FX32_ONE);
	{
		//バインドターゲットとの差分
		VecFx32 look_at = GFC_GetLookTarget(camera_ptr);
		const VecFx32 *bind = GFC_GetBindTargetVecPtr(camera_ptr);

		OS_Printf("オフセット：%x,%x,%x\n",
				look_at.x-bind->x, look_at.y-bind->y, look_at.z-bind->z);
	}
}

#endif //PM_DEBUG

//----------------------------------------------------------------------------
/**
 *	@brief	シートの位置セット
 *
 *	@param		inX			X座標
 *	@param		inY			Y座標
 *	@param		outPoint	シート座標格納バッファ
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void SetSeetPoint( const u32 inX, const fx32 inY, fx32 *outPoint)
{
	int i;
	int left,right;
	fx32 dif;
	dif =  -inY;
	//左側のジャンプポイント数
	left = inX;
	right = (JUMP_POINT_NUM-1) - inX;
	for(i=0;i<left;i++){
		u8 val;
		val = i+1;
		outPoint[i] = -( (dif*val)/(left+1) );
	}

	//右側のジャンプポイント数
	for(i=0;i<right;i++){
		u8 idx;
		u8 val;
		idx = inX+1+i;
		val = right-i;
		outPoint[idx] = -( (dif*val)/(right+1) );
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	シミュレーターボールをシートの位置にセット
 *
 *	@param		ptr		競技ポインタ
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void AdsorbBall(PKTHLN_JUMP_PTR ptr)
{
	int i;
	BALL *ball;
	SEET_DAT *seet;
	seet = &ptr->SeetDat;
	for(i=0;i<ENTRY_MAX;i++){
		ball = &ptr->Ball[i];
		if (!ball->Move){
			ball->Pos.y = seet->Point[ seet->JumpPoint[i] ];
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	テンポラリ座標のセット
 *
 *	@param		ptr		競技ポインタ
 *	@param		inIdx	インデックス
 *	@param		inPos	X座標
 *	@param		inVal	シミュレータボールのY座標
 *
 *	@return 	none
 */
//-----------------------------------------------------------------------------
static void SetTmpPoint(PKTHLN_JUMP_PTR ptr, const u8 inIdx, const u8 inPos, const fx32 inVal)
{
	int i;
	for (i=0;i<JUMP_POINT_NUM;i++){
		ptr->SeetDat.TempPoint[inIdx][i] = 0;
	}
	ptr->SeetDat.TempPoint[inIdx][inPos] = inVal;
	SetSeetPoint( inPos, ptr->SeetDat.TempPoint[inIdx][inPos], ptr->SeetDat.TempPoint[inIdx]);
}

//----------------------------------------------------------------------------
/**
 *	@brief		ＯＢＪセット
 *
 *	@param	pActCntPtr		アクターコントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetObj(PKTHLN_CLACT_CNT_PTR pActCntPtr)
{
	PkthlnClAct_SetChar( pActCntPtr,
					ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_obj_cmn_NCGR,
					RES_CODE_JUMP, NNS_G2D_VRAM_TYPE_MAX);
	PkthlnClAct_SetPaltt( pActCntPtr,
					ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_obj_cmn_NCLR,
					RES_CODE_JUMP, NNS_G2D_VRAM_TYPE_MAX, JUMP_OBJ_PALETTE_NUM	);
	PkthlnClAct_SetCell( pActCntPtr,
					ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_obj_cmn_NCER, RES_CODE_JUMP	);
	PkthlnClAct_SetAnm(	pActCntPtr,
					ARC_PKTHEV_JUMP, NARC_pkthev_jump_jump_obj_cmn_NANR, RES_CODE_JUMP	);
}

//----------------------------------------------------------------------------
/**
 *	@brief		セットアップ
 *
 *	@param	ptr			コントローラポインタ
 *	@param	pActCntPtr	アクターコントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetAct( PKTHLN_JUMP_PTR ptr, PKTHLN_CLACT_CNT_PTR pActCntPtr)
{
	int i;
	//ランプ
	Lmp_SetAct(ptr->LampCntPtr, pActCntPtr, 2);
	//時計
	ptr->WatchActPtr = PkthlnClAct_SetGetActor(pActCntPtr, BG_PRI, NNS_G2D_VRAM_TYPE_MAX, RES_CODE_JUMP, ACT_CODE_JUMP_WATCH);
	PkthlnClAct_ChgAnm(ptr->WatchActPtr, 12);
	PkthlnClAct_SetActive(ptr->WatchActPtr, 1, 1);	//可視化
	//旗
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		ptr->FlagActPtr[i] = PkthlnClAct_SetGetActor(pActCntPtr, BG_PRI, NNS_G2D_VRAM_TYPE_MAX, RES_CODE_JUMP, ACT_CODE_JUMP_FLAG);
		PkthlnClAct_ChgAnm(ptr->FlagActPtr[i], 13+i);
		PkthlnClAct_SetActive(ptr->FlagActPtr[i], 1, 1);	//可視化
	}

	//ステート
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		u8 j;
		ptr->Poke[i].PanicActPtr = PkthlnClAct_SetGetActor(pActCntPtr, BG_PRI, NNS_G2D_VRAM_TYPE_MAX, RES_CODE_JUMP, ACT_CODE_JUMP_PANIC);
		PkthlnClAct_ChgAnm(ptr->Poke[i].PanicActPtr, 11);
		PkthlnClAct_SetPriority(ptr->Poke[i].PanicActPtr, PRI_PANIC);
	}

	//ヒットエフェクト
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		ptr->HitActPtr[i] = PkthlnClAct_SetGetActor(pActCntPtr, BG_PRI, NNS_G2D_VRAM_TYPE_MAX, RES_CODE_JUMP, ACT_CODE_JUMP_HIT);
		PkthlnClAct_ChgAnm(ptr->HitActPtr[i], 9);
		PkthlnClAct_SetPriority(ptr->HitActPtr[i], PRI_HIT);
	}
/**
	//砂煙エフェクト
	for(i=0;i<SND_EFFECT_NUM;i++){
		ptr->SndActPtr[i] = PkthlnClAct_SetGetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_STL_MAIN, ACT_CODE_STL_SND);
		PkthlnClAct_ChgAnm(ptr->SndActPtr[i], 4);
	}

	//旗・煙
	for(i=0;i<FLAG_DISP_MAX;i++){
		ptr->FlagData.Flag[i].EffActPtr = PkthlnClAct_SetGetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_STL_MAIN, ACT_CODE_STL_FSMG);
		ptr->FlagData.Flag[i].ActPtr = PkthlnClAct_SetGetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_STL_MAIN, ACT_CODE_STL_FLAG);
		PkthlnClAct_ChgAnm(ptr->FlagData.Flag[i].ActPtr, 0);
		PkthlnClAct_ChgAnm(ptr->FlagData.Flag[i].EffActPtr, 4);
	}
*/
	//共有リソースからアクター取得
	for(i=0;i<TIMER_ACT_NUM;i++){
		VecFx32 vec;
		ptr->TimeNumActPtr[i] = CmnRes_CreateF2X2S256Act( ptr->CmnResCntPtr,
														  PkthlnClAct_GetClActSetAdr(pActCntPtr),
														  BG_PRI,
														  ptr->HeapID );
		CLACT_SetDrawFlag(ptr->TimeNumActPtr[i], 1);	//表示

		vec.x = TimerActPosX[i] * FX32_ONE;
		vec.y = TIMER_ACT_POS_Y * FX32_ONE;
		vec.z = 0;
		//タイマーアクターの座標セット
		CLACT_SetMatrix(ptr->TimeNumActPtr[i], &vec);
		CLACT_AnmChg(ptr->TimeNumActPtr[i], DefaultTimerActAnm[i]);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief		OBJ座標セット
 *
 *	@param	ptr			コントローラポインタ
 *	@param	inMyNetID	ネットID
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetActPos( PKTHLN_JUMP_PTR ptr, const u8 inMyNetID)
{
	//ランプ
	Lmp_SetPos(ptr->LampCntPtr);
	//時計
	{
		VecFx32 vec = {WATCH_POS_X, WATCH_POS_Y, 0};
		PkthlnClAct_SetPos(ptr->WatchActPtr, &vec);
	}
	//旗
	{
		int i;
		u8 count;
		VecFx32 vec = {MY_FLAG_POS_X, MY_FLAG_POS_Y, 0};
		//自分の旗の位置を決定
		PkthlnClAct_SetPos(ptr->FlagActPtr[inMyNetID], &vec);

		count = 0;
		for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			VecFx32 vec = {OTHER_FLAG_POS_X, OTHER_FLAG_POS_Y_BASE, 0};
			if (i == inMyNetID){
				continue;
			}
			vec.y += OTHER_FLAG_POS_Y_MARGINE * count;
			PkthlnClAct_SetPos(ptr->FlagActPtr[i], &vec);
			count++;
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点表示
 *
 *	@param	ptr	コントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DispTotalScore(PKTHLN_JUMP_PTR ptr)
{
	int i;
	u16 total = 0;
	for(i=0;i<ENTRY_MAX;i++){
		total += ptr->Poke[i].Score;
	}
	if (total > GAME_SCORE_MAX){
		total = GAME_SCORE_MAX;
	}
	DispScore(ptr, total);
}

//----------------------------------------------------------------------------
/**
 *	@brief	得点表示
 *
 *	@param	ptr	コントローラポインタ
 *	@param	inScore		表示スコア
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DispScore(PKTHLN_JUMP_PTR ptr, const u16 inScore)
{
	u8 i;
	u8 h,t,o;
	u8 read_x[SCORE_DIGI_MAX];
	u8 read_y[SCORE_DIGI_MAX];

	//3桁の点数を3つに分解
	h = inScore/100;
	t = (inScore-(h*100)) / 10;
	o = inScore%10;

	//データ読み込み位置を算出(数字スクリーンデータに依存)
	read_x[0] = (h%NUMBER_SCR_NUM_W)*SCORE_NUMBER_W;
	read_y[0] = (h/NUMBER_SCR_NUM_W)*SCORE_NUMBER_H;
	read_x[1] = (t%NUMBER_SCR_NUM_W)*SCORE_NUMBER_W;
	read_y[1] = (t/NUMBER_SCR_NUM_W)*SCORE_NUMBER_H;
	read_x[2] = (o%NUMBER_SCR_NUM_W)*SCORE_NUMBER_W;
	read_y[2] = (o/NUMBER_SCR_NUM_W)*SCORE_NUMBER_H;

	for (i=0;i<SCORE_DIGI_MAX;i++){
		GF_BGL_ScrWriteFree(ptr->bgl, GF_BGL_FRAME0_S,
				SCORE_DISP_START_X+(i*SCORE_NUMBER_W), SCORE_DISP_START_Y,
				SCORE_NUMBER_W, SCORE_NUMBER_H,
				&ptr->ScoreScrnData->rawData,
				read_x[i], read_y[i], SCORE_NUMBER_W*NUMBER_SCR_NUM_W, SCORE_NUMBER_H*NUMBER_SCR_NUM_H );
	}

	GF_BGL_LoadScreenV_Req(ptr->bgl, GF_BGL_FRAME0_S);
}

//----------------------------------------------------------------------------
/**
 *	@brief	時間表示
 *
 *	@param	ptr			コントローラポインタ
 *	@param	inTime		時間
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DispTime(PKTHLN_JUMP_PTR ptr, const u16 inTime)
{
	u8 sec,sec_t,sec_o;

	//秒計算
	sec = inTime / 30;

	sec_t = sec / 10;
	sec_o = sec % 10;

	//秒を書き換え
	CLACT_AnmChg(ptr->TimeNumActPtr[0], sec_t+1);
	CLACT_AnmChg(ptr->TimeNumActPtr[1], sec_o+1);
}

//--------------------------------------------------------------------------------------------
/**
 * 情報表示
 *
 * @param	work	ポケスロンワークポインタ
 * @param	ptr		管理ポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void WriteName( PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr )
{
	u8 i;
	for(i=0;i<WIN_MAX;i++){
		GF_BGL_BmpWinDataFill( &ptr->Win[i], 0);
	}

	//名前
	{
		u8 win_cnt;
		u8 my_id;
		//第一枠は必ず自分の名前
		STRBUF *name_buf;

		my_id = PTFrameGetCurrentID(work);
		//マイステータスにアクセスして名前取得
		name_buf = MyStatus_CreateNameString(
				PTFrame_GetMyStatus(work, my_id),
				ptr->HeapID);
		GF_STR_PrintColor( 	&ptr->Win[0], FONT_SYSTEM, name_buf,
				0, 0, MSG_NO_PUT, BAGCOL_N_WHITE, NULL );
		STRBUF_Delete(name_buf);

		win_cnt = 1;
		//２枠からは他プレーヤー
		for (i=0; i<ENTRY_MEMBER_NUM_MAX; i++){
			STRBUF *name_buf;
			if (i==my_id){
				continue;
			}
			//マイステータスにアクセスして名前取得
			name_buf = MyStatus_CreateNameString(
					PTFrame_GetMyStatus(work, i),
					ptr->HeapID);
			GF_STR_PrintColor( 	&ptr->Win[win_cnt], FONT_SYSTEM, name_buf,
					0, 0, MSG_NO_PUT, BAGCOL_N_WHITE, NULL );
			STRBUF_Delete(name_buf);

			win_cnt++;
		}
	}

	for(i=0;i<WIN_MAX;i++){
		GF_BGL_BmpWinOn(&ptr->Win[i]);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * BMPウィンドウ追加
 *
 * @param 	ptr			コントローラポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CreateBmpWin( PKTHLN_JUMP_PTR ptr )
{
	u8 i;
	const BMPWIN_DAT * dat = JumpEvtBmpData;
	for(i=0;i<WIN_MAX;i++){
		GF_BGL_BmpWinAddEx( ptr->bgl, &(ptr->Win[i]), &dat[i] );
	}
	//先頭キャラをクリア（スクリーンクリアされてるところは、このキャラで埋まる）
	GF_BGL_CharFill( ptr->bgl, MSG_BG, 0, 1, 0 );
	//システム用フォントパレット転送
	SystemFontPaletteLoad(PALTYPE_SUB_BG, JUMP_SYS_FONT_PAL*32, ptr->HeapID);

	//先頭キャラをクリア（スクリーンクリアされてるところは、このキャラで埋まる）
	GF_BGL_CharFill( ptr->bgl, REC_BG, 0, 1, 0 );
	//システム用フォントパレット転送
	SystemFontPaletteLoad(PALTYPE_MAIN_BG, REC_FONT_PAL*32, ptr->HeapID);
}

//----------------------------------------------------------------------------
/**
 *	@brief		レコード文字列展開
 *
 *	@param	ptr		コントローラポインタ
 *	@param	inScore	得点
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetRecordStr(PKTHLN_JUMP_PTR ptr, const u16 inScore)
{
	WORDSET *word;
	STRBUF * str;
	MSGDATA_MANAGER *msgman;
	int integer;

	GF_BGL_BmpWinDataFill( &ptr->Win[WIN_MAX-1], 0);

	//整数部分
	integer = inScore;

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG, NARC_msg_pokethlon_dat, ptr->HeapID);
    word = WORDSET_Create(ptr->HeapID);
	WORDSET_RegisterNumber(word, 0, integer, 3,
				NUMBER_DISPTYPE_SPACE,NUMBER_CODETYPE_DEFAULT);

    str = MSGDAT_UTIL_AllocExpandString(word, msgman, msg_pkthln_new_record06, ptr->HeapID);

	GF_STR_PrintColor( 	&ptr->Win[WIN_MAX-1], FONT_TOUCH, str,
					0, 0, MSG_NO_PUT, COL_N_WHITE, NULL );
	STRBUF_Delete(str);//<一括表示なので、メモリをここで消してもOK
	WORDSET_Delete( word );
	MSGMAN_Delete( msgman );

	GF_BGL_BmpWinOn(&ptr->Win[WIN_MAX-1]);
}

//----------------------------------------------------------------------------
/**
 *
 *	@brief	横移動スピードの減速
 *
 *	@param	poke		ジャンプポケモン
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DecSideSpeed(JUMP_POKE *poke)
{
	if (poke->DispXSpd == 0){
		return;
	}
	if (poke->DispXSpd > 0){
		poke->DispXSpd -= (DEC_SIDE_SPEED*FX32_ONE);
		if (poke->DispXSpd < 0){
			poke->DispXSpd = 0;
		}
	}else if(poke->DispXSpd < 0){
		poke->DispXSpd += (DEC_SIDE_SPEED*FX32_ONE);
		if (poke->DispXSpd > 0){
			poke->DispXSpd = 0;
		}
	}
}

//--------------------------------------------------------------------------------------------
/**
 * パラメータセット
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*inData		パラメータ
 * @param	inIdx		ポケモンエントリーインデックス0〜2
 * @param	*outPoke	パラメータ格納場所
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetPokeParam(	PKTHLN_PTR work, const JUMP_PARAM *inData,
							const u8 inIdx, JUMP_POKE *outPoke)
{
	u8 net_id;
	const POKE_SPEC *spec;
	net_id = PTFrameGetCurrentID(work);
	spec = PTFrame_GetPokeSpec(work, net_id, inIdx);

	OS_Printf("%d::jp:st:tq = %d,%d,%d\n",
			inIdx,spec->Jump,spec->Stamina,spec->Technique);

	outPoke->Jump = inData->Jump[spec->Jump];
	outPoke->PanicTime = inData->PanicTime[spec->Stamina];
	outPoke->Step = inData->Step[spec->Technique];
}

//--------------------------------------------------------------------------------------------
/**
 * 当たり判定
 *
 * @param	work		ポケスロンワークポインタ
 * @param	ptr			競技ポインタ
 *
 * @return	BOOL		TRUEでヒット
 */
//--------------------------------------------------------------------------------------------
static BOOL HitCheck(PKTHLN_PTR work, PKTHLN_JUMP_PTR ptr)
{
	int i,j;
	JUMP_POKE *poke1;
	JUMP_POKE *poke2;
	BALL * ball1;
	BALL * ball2;

	for(i=0;i<ENTRY_MAX;i++){
		poke1 = &ptr->Poke[i];
		ball1 = &ptr->Ball[i];
		for(j=0;j<ENTRY_MAX;j++){
			if (i==j){
				continue;
			}
			poke2 = &ptr->Poke[j];
			ball2 = &ptr->Ball[j];

			//ヒットチェック
			{
				POKE_ACT_PTR poke_ptr1, poke_ptr2;
				VecFx32 vec1, vec2;
				int range1, range2;
				int tx,ty;
				int sx, sy;

				u8 my_net_id;

				my_net_id = PTFrameGetCurrentID(work);

				poke_ptr1 = poke1->PokeActPtr;
				poke_ptr2 = poke2->PokeActPtr;

				sx = poke1->DispXTmp / FX32_ONE;
				sy = ( MAIN_SUB_DIST + GROUND_BASE_OFS - (ball1->Pos.y * CONF_3D_TO_2D) ) / FX32_ONE;
				PokeAct_GetTouchPosByShadowPos(	poke_ptr1, sx, sy,	&tx, &ty);
				PokeAct_GetHitData(poke_ptr1, tx*FX32_ONE, ty*FX32_ONE, &vec1.x, &vec1.y, &range1);
				vec1.z = 0;

				sx = poke2->DispXTmp / FX32_ONE;
				sy = ( MAIN_SUB_DIST + GROUND_BASE_OFS - (ball2->Pos.y * CONF_3D_TO_2D) ) / FX32_ONE;
				PokeAct_GetTouchPosByShadowPos(	poke_ptr2, sx,	sy,	&tx, &ty);
				PokeAct_GetHitData(poke_ptr2, tx*FX32_ONE, ty*FX32_ONE, &vec2.x, &vec2.y, &range2);
				vec2.z = 0;

				if ( !CheckCircle(&vec1, range1*FX32_ONE, &vec2, range2*FX32_ONE) ){
					//ヒットしていないので、ヒット状態をクリア
					poke1->Hit[j] = 0;
					poke2->Hit[i] = 0;
/**
#ifdef PM_DEBUG
					if (i==1 && j==2){
						OS_Printf("ヒッチ解消\n");
					}
#endif
*/
					continue;
				}

				if ( poke2->Hit[i] ){
					//既にヒット済み
					continue;
				}

				//気絶フラグ立てる
				poke1->PanicState = 1;
				poke2->PanicState = 1;
				poke1->PanicCount = (poke1->PanicTime * 30) / PANIC_DIV_CONF;
				poke2->PanicCount = (poke2->PanicTime * 30) / PANIC_DIV_CONF;
				//ヒットエフェクト座標を計算
				{
					VecFx32 vec = {0,0,0};
					fx32 r;

					//自分からターゲットへのベクトル
					VEC_Subtract(&vec2, &vec1, &vec);
					//正規化
					VEC_Normalize(&vec, &vec);
					//自分の半径倍する
					r = range1*FX32_ONE;
					VEC_MultAdd(r,&vec,&vec1,&vec);
					ptr->HitVec[ ptr->HitIdx ] = vec;
					ptr->HitFlg[ ptr->HitIdx ] = 1;
					OS_Printf("ヒットエフェクト：%d,%d\n",ptr->HitVec[ ptr->HitIdx ].x/FX32_ONE, ptr->HitVec[ ptr->HitIdx ].y/FX32_ONE);
					ptr->HitIdx = (ptr->HitIdx+1)%JUMP_EVENT_POKE_NUM;
					//ポケモンぶつかりSE
					Snd_SePlayEx( SE_JUMP_HIT, SndPlayer[HIT_SE_IDX] );
				}
				//アクションポイント加算「体当たり」
				PTFrame_AddActionPoint(	work, my_net_id, i, ADD_TYPE_ATTACK, 1 );
				PTFrame_AddActionPoint(	work, my_net_id, j, ADD_TYPE_ATTACK, 1 );
				//アクションポイント加算「失敗回数」
				PTFrame_AddActionPoint(	work, my_net_id, i, ADD_TYPE_FAIL, 1 );
				PTFrame_AddActionPoint(	work, my_net_id, j, ADD_TYPE_FAIL, 1 );
			}

			//地上での衝突かで分岐
			if ( (ball1->Fly && ball2->Fly) &&
				 ( (ball1->Pos.y > 0)&&(ball2->Pos.y > 0) ) ){	//空中
				fx32 speed;
				if ( poke1->Hit[j] || poke2->Hit[i] ){
					//まだ接触しているので離れるまでチェックしない
					continue;
				}
				OS_Printf("空中\n");
				//ヒットを記憶
				poke1->Hit[j] = 1;
				poke2->Hit[i] = 1;

				speed = ball2->Speed;
				ball2->Speed = ball1->Speed;
				ball1->Speed = speed;
				speed = poke2->DispXSpd;
				poke2->DispXSpd = poke1->DispXSpd;
				poke1->DispXSpd = speed;

				if (ball1->Speed < 0){
					ball1->Speed = 0;
				}
				if (ball2->Speed < 0){
					ball2->Speed = 0;
				}
			}else{		//地上
				OS_Printf("地上\n");
				//お互いを離す
				if (poke1->DispXTmp <= poke2->DispXTmp){
					poke1->DispXTmp-=( 16*FX32_ONE);
					poke2->DispXTmp+=( 16*FX32_ONE);
				}else{
					poke1->DispXTmp+=( 16*FX32_ONE);
					poke2->DispXTmp-=( 16*FX32_ONE);
				}
				//X移動制限
				if (poke1->DispXTmp < X_MIN*FX32_ONE){
					poke1->DispXTmp = X_MIN*FX32_ONE;
				}else if(poke1->DispXTmp > X_MAX*FX32_ONE){
					poke1->DispXTmp = X_MAX*FX32_ONE;
				}
				//X移動制限
				if (poke2->DispXTmp < X_MIN*FX32_ONE){
					poke2->DispXTmp = X_MIN*FX32_ONE;
				}else if(poke2->DispXTmp > X_MAX*FX32_ONE){
					poke2->DispXTmp = X_MAX*FX32_ONE;
				}
			}

		}
	}
	return FALSE;
}
